home *** CD-ROM | disk | FTP | other *** search
/ Chip 2005 August (Alt) / CHIP 2005-08.1.iso / program / code / Firefox_1.0.5.exe / browser.xpi / bin / chrome / browser.jar / content / browser / browser.js < prev    next >
Encoding:
Text File  |  2005-07-07  |  195.3 KB  |  5,463 lines

  1.  
  2. const NS_ERROR_MODULE_NETWORK = 2152398848;
  3. const NS_NET_STATUS_READ_FROM = NS_ERROR_MODULE_NETWORK + 8;
  4. const NS_NET_STATUS_WROTE_TO  = NS_ERROR_MODULE_NETWORK + 9;
  5. const kXULNS = 
  6.     "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
  7.  
  8. const nsCI               = Components.interfaces;
  9. const nsIWebNavigation   = nsCI.nsIWebNavigation;
  10.  
  11. const MAX_HISTORY_MENU_ITEMS = 15;
  12.  
  13. var gRDF = null;
  14. var gGlobalHistory = null;
  15. var gURIFixup = null;
  16. var gPageStyleButton = null;
  17. var gLivemarksButton = null;
  18. var gCharsetMenu = null;
  19. var gLastBrowserCharset = null;
  20. var gPrevCharset = null;
  21. var gURLBar = null;
  22. var gProxyButton = null;
  23. var gProxyFavIcon = null;
  24. var gProxyDeck = null;
  25. var gNavigatorBundle = null;
  26. var gIsLoadingBlank = false;
  27. var gLastValidURLStr = "";
  28. var gLastValidURL = null;
  29. var gHaveUpdatedToolbarState = false;
  30. var gClickSelectsAll = false;
  31. var gIgnoreFocus = false;
  32. var gIgnoreClick = false;
  33. var gMustLoadSidebar = false;
  34. var gProgressMeterPanel = null;
  35. var gProgressCollapseTimer = null;
  36. var gPrefService = null;
  37. var appCore = null;
  38. var gBrowser = null;
  39. var gSidebarCommand = "";
  40.  
  41. // Global variable that holds the nsContextMenu instance.
  42. var gContextMenu = null;
  43.  
  44. var gChromeState = null; // chrome state before we went into print preview
  45.  
  46. var gFormFillPrefListener = null;
  47. var gFormHistory = null;
  48. var gFormFillEnabled = true;
  49.  
  50. var gURLBarAutoFillPrefListener = null;
  51.  
  52. /**
  53. * We can avoid adding multiple load event listeners and save some time by adding
  54. * one listener that calls all real handlers.
  55. */
  56.  
  57. function loadEventHandlers(event)
  58. {
  59.   // Filter out events that are not about the document load we are interested in
  60.   if (event.originalTarget == _content.document) {
  61.     checkForDirectoryListing();
  62.     charsetLoadListener(event);
  63.     updatePageLivemarks();
  64.   }
  65.  
  66.   // some event handlers want to be told what the original browser/listener is
  67.   var targetBrowser = null;
  68.   var targetListener = null;
  69.   if (gBrowser.mTabbedMode) {
  70.     var targetBrowserIndex = gBrowser.getBrowserIndexForDocument(event.originalTarget);
  71.     if (targetBrowserIndex == -1)
  72.       return;
  73.     targetBrowser = gBrowser.getBrowserAtIndex(targetBrowserIndex);
  74.     targetListener = gBrowser.mTabListeners[targetBrowserIndex];
  75.   } else {
  76.     targetBrowser = gBrowser.mCurrentBrowser;
  77.     targetListener = null;      // no listener for non-tabbed-mode
  78.   }
  79.  
  80.   updatePageFavIcon(targetBrowser, targetListener);
  81.  
  82.   // update the last visited date
  83.   if (targetBrowser.currentURI.spec)
  84.     BMSVC.updateLastVisitedDate(targetBrowser.currentURI.spec,
  85.                                 targetBrowser.contentDocument.characterSet);
  86. }
  87.  
  88. /**
  89.  * Determine whether or not the content area is displaying a page with frames,
  90.  * and if so, toggle the display of the 'save frame as' menu item.
  91.  **/
  92. function getContentAreaFrameCount()
  93. {
  94.   var saveFrameItem = document.getElementById("menu_saveFrame");
  95.   if (!content || !_content.frames.length || !isDocumentFrame(document.commandDispatcher.focusedWindow))
  96.     saveFrameItem.setAttribute("hidden", "true");
  97.   else
  98.     saveFrameItem.removeAttribute("hidden");
  99. }
  100.  
  101. function UpdateBackForwardButtons()
  102. {
  103.   var backBroadcaster = document.getElementById("Browser:Back");
  104.   var forwardBroadcaster = document.getElementById("Browser:Forward");
  105.   
  106.   var webNavigation = gBrowser.webNavigation;
  107.  
  108.   // Avoid setting attributes on broadcasters if the value hasn't changed!
  109.   // Remember, guys, setting attributes on elements is expensive!  They
  110.   // get inherited into anonymous content, broadcast to other widgets, etc.!
  111.   // Don't do it if the value hasn't changed! - dwh
  112.  
  113.   var backDisabled = backBroadcaster.hasAttribute("disabled");
  114.   var forwardDisabled = forwardBroadcaster.hasAttribute("disabled");
  115.   if (backDisabled == webNavigation.canGoBack) {
  116.     if (backDisabled)
  117.       backBroadcaster.removeAttribute("disabled");
  118.     else
  119.       backBroadcaster.setAttribute("disabled", true);
  120.   }
  121.   
  122.   if (forwardDisabled == webNavigation.canGoForward) {
  123.     if (forwardDisabled)
  124.       forwardBroadcaster.removeAttribute("disabled");
  125.     else
  126.       forwardBroadcaster.setAttribute("disabled", true);
  127.   }
  128. }
  129.  
  130. const gSessionHistoryObserver = {
  131.   observe: function(subject, topic, data)
  132.   {
  133.     if (topic != "browser:purge-session-history")
  134.       return;
  135.  
  136.     var backCommand = document.getElementById("Browser:Back");
  137.     backCommand.setAttribute("disabled", "true");
  138.     var fwdCommand = document.getElementById("Browser:Forward");
  139.     fwdCommand.setAttribute("disabled", "true");
  140.   }
  141. };
  142.  
  143. const gPopupBlockerObserver = {
  144.   _reportButton: null,
  145.   _kIPM: Components.interfaces.nsIPermissionManager,
  146.   
  147.   onUpdatePageReport: function ()
  148.   {
  149.     if (!this._reportButton) 
  150.       this._reportButton = document.getElementById("page-report-button");
  151.     
  152.     if (gBrowser.selectedBrowser.pageReport) {
  153.       this._reportButton.setAttribute("blocked", "true");
  154.       if (gPrefService && gPrefService.getBoolPref("privacy.popups.showBrowserMessage")) {
  155.         var bundle_browser = document.getElementById("bundle_browser");
  156.         var brandBundle = document.getElementById("bundle_brand");
  157.         var brandShortName = brandBundle.getString("brandShortName");
  158.         var message;
  159.         var popupCount = gBrowser.selectedBrowser.pageReport.length;
  160.         if (popupCount > 1) 
  161.           message = bundle_browser.getFormattedString("popupWarningMultiple", [brandShortName, popupCount]);
  162.         else
  163.           message = bundle_browser.getFormattedString("popupWarning", [brandShortName]);
  164.         gBrowser.showMessage(gBrowser.selectedBrowser, "chrome://browser/skin/Info.png", 
  165.                              message, "", null, null, "blockedPopupOptions", "top", true);
  166.       }
  167.     }
  168.     else
  169.       this._reportButton.removeAttribute("blocked");
  170.   },
  171.   
  172.   toggleAllowPopupsForSite: function (aEvent)
  173.   {
  174.     var currentURI = gBrowser.selectedBrowser.webNavigation.currentURI;
  175.     var pm = Components.classes["@mozilla.org/permissionmanager;1"]
  176.                        .getService(this._kIPM);
  177.     var shouldBlock = aEvent.target.getAttribute("block") == "true";
  178.     var perm = shouldBlock ? this._kIPM.DENY_ACTION : this._kIPM.ALLOW_ACTION;
  179.     pm.add(currentURI, "popup", perm);
  180.     
  181.     gBrowser.hideMessage(gBrowser.selectedBrowser, "top");
  182.   },
  183.   
  184.   fillPopupList: function (aEvent)
  185.   {
  186.     var bundle_browser = document.getElementById("bundle_browser");
  187.     // XXXben - rather than using |currentURI| here, which breaks down on multi-framed sites
  188.     //          we should really walk the pageReport and create a list of "allow for <host>"
  189.     //          menuitems for the common subset of hosts present in the report, this will
  190.     //          make us frame-safe.
  191.     var uri = gBrowser.selectedBrowser.webNavigation.currentURI;
  192.     var blockedPopupAllowSite = document.getElementById("blockedPopupAllowSite");
  193.     try {
  194.       blockedPopupAllowSite.removeAttribute("hidden");
  195.       
  196.       var pm = Components.classes["@mozilla.org/permissionmanager;1"]
  197.                         .getService(this._kIPM);
  198.       if (pm.testPermission(uri, "popup") == this._kIPM.ALLOW_ACTION) {
  199.         // Offer an item to block popups for this site, if a whitelist entry exists
  200.         // already for it.
  201.         var blockString = bundle_browser.getFormattedString("popupBlock", [uri.host]);
  202.         blockedPopupAllowSite.setAttribute("label", blockString);
  203.         blockedPopupAllowSite.setAttribute("block", "true");
  204.       }
  205.       else {
  206.         // Offer an item to allow popups for this site
  207.         var allowString = bundle_browser.getFormattedString("popupAllow", [uri.host]);
  208.         blockedPopupAllowSite.setAttribute("label", allowString);
  209.         blockedPopupAllowSite.removeAttribute("block");
  210.       }
  211.     }
  212.     catch (e) {
  213.       blockedPopupAllowSite.setAttribute("hidden", "true");
  214.     }
  215.     
  216.     var item = aEvent.target.lastChild;
  217.     while (item && item.getAttribute("observes") != "blockedPopupsSeparator") {
  218.       var next = item.previousSibling;
  219.       item.parentNode.removeChild(item);
  220.       item = next;
  221.     }
  222.     var pageReport = gBrowser.selectedBrowser.pageReport;
  223.     if (pageReport && pageReport.length > 0) {
  224.       var blockedPopupsSeparator = document.getElementById("blockedPopupsSeparator");
  225.       blockedPopupsSeparator.removeAttribute("hidden");
  226.       for (var i = 0; i < pageReport.length; ++i) {
  227.         var popupURIspec = pageReport[i].popupWindowURI.spec;
  228.         if (popupURIspec == "" || popupURIspec == "about:blank" ||
  229.             popupURIspec == uri.spec)
  230.           continue;
  231.  
  232.         var menuitem = document.createElement("menuitem");
  233.         var label = bundle_browser.getFormattedString("popupShowPopupPrefix", 
  234.                                                       [popupURIspec]);
  235.         menuitem.setAttribute("label", label);
  236.         menuitem.setAttribute("requestingWindowURI", pageReport[i].requestingWindowURI.spec);
  237.         menuitem.setAttribute("popupWindowURI", popupURIspec);
  238.         menuitem.setAttribute("popupWindowFeatures", pageReport[i].popupWindowFeatures);
  239.         menuitem.setAttribute("oncommand", "gPopupBlockerObserver.showBlockedPopup(event);");
  240.         aEvent.target.appendChild(menuitem);
  241.       }
  242.     }
  243.     else {
  244.       var blockedPopupsSeparator = document.getElementById("blockedPopupsSeparator");
  245.       blockedPopupsSeparator.setAttribute("hidden", "true");
  246.     }
  247.         
  248.     var blockedPopupDontShowMessage = document.getElementById("blockedPopupDontShowMessage");
  249.     var showMessage = gPrefService.getBoolPref("privacy.popups.showBrowserMessage");
  250.     blockedPopupDontShowMessage.setAttribute("checked", !showMessage);
  251.     if (aEvent.target.localName == "popup")
  252.       blockedPopupDontShowMessage.setAttribute("label", bundle_browser.getString("popupWarningDontShowFromMessage"));
  253.     else
  254.       blockedPopupDontShowMessage.setAttribute("label", bundle_browser.getString("popupWarningDontShowFromStatusbar"));
  255.   },
  256.   
  257.   _findChildShell: function (aDocShell, aSoughtURI)
  258.   {
  259.     var webNav = aDocShell.QueryInterface(Components.interfaces.nsIWebNavigation);
  260.     if (webNav.currentURI.spec == aSoughtURI.spec)
  261.       return aDocShell;
  262.       
  263.     var node = aDocShell.QueryInterface(Components.interfaces.nsIDocShellTreeNode);
  264.     for (var i = 0; i < node.childCount; ++i) {
  265.       var docShell = node.getChildAt(i);
  266.       docShell = this._findChildShell(docShell, aSoughtURI);
  267.       if (docShell)
  268.         return docShell;
  269.     }
  270.     return null;
  271.   },
  272.  
  273.   showBlockedPopup: function (aEvent)
  274.   {
  275.     var requestingWindowURI = Components.classes["@mozilla.org/network/standard-url;1"]
  276.                                         .createInstance(Components.interfaces.nsIURI);
  277.     requestingWindowURI.spec = aEvent.target.getAttribute("requestingWindowURI");
  278.     var popupWindowURI = aEvent.target.getAttribute("popupWindowURI");
  279.     var features = aEvent.target.getAttribute("popupWindowFeatures");
  280.     
  281.     var shell = this._findChildShell(gBrowser.selectedBrowser.docShell, 
  282.                                      requestingWindowURI);
  283.     if (shell) {
  284.       var ifr = shell.QueryInterface(Components.interfaces.nsIInterfaceRequestor);
  285.       var dwi = ifr.getInterface(Components.interfaces.nsIDOMWindowInternal);
  286.       // XXXben - nsIDOMPopupBlockedEvent needs to store target, too!
  287.       dwi.open(popupWindowURI, "", features);
  288.     }
  289.   },
  290.   
  291.   editPopupSettings: function ()
  292.   {
  293.     var host = "";
  294.     try {
  295.       var uri = gBrowser.selectedBrowser.webNavigation.currentURI;
  296.       host = uri.host;
  297.     }
  298.     catch (e) { } 
  299.  
  300.     var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
  301.                         .getService(Components.interfaces.nsIWindowMediator);
  302.     var existingWindow = wm.getMostRecentWindow("exceptions");
  303.     if (existingWindow) {
  304.       existingWindow.setHost(host);
  305.       existingWindow.focus();
  306.     }
  307.     else {
  308.       var params = { blockVisible: false, 
  309.                      allowVisible: true, 
  310.                      prefilledHost: host, 
  311.                      permissionType: "popup" };
  312.       window.openDialog("chrome://browser/content/cookieviewer/CookieExceptions.xul?permission=popup",
  313.                         "_blank", "chrome,modal,resizable=yes", params);
  314.     }
  315.   },
  316.   
  317.   dontShowMessage: function ()
  318.   {
  319.     var showMessage = gPrefService.getBoolPref("privacy.popups.showBrowserMessage");
  320.     var firstTime = gPrefService.getBoolPref("privacy.popups.firstTime");
  321.     
  322.     // If the info message is showing at the top of the window, and the user has never 
  323.     // hidden the message before, show an info box telling the user where the info
  324.     // will be displayed. 
  325.     if (showMessage && firstTime)
  326.       this._displayPageReportFirstTime();
  327.  
  328.     gPrefService.setBoolPref("privacy.popups.showBrowserMessage", !showMessage);
  329.  
  330.     gBrowser.hideMessage(gBrowser.selectedBrowser, "top");
  331.   },
  332.  
  333.   _displayPageReportFirstTime: function ()
  334.   {
  335.     window.openDialog("chrome://browser/content/pageReportFirstTime.xul", "_blank",
  336.                       "dependent");
  337.   }
  338. };
  339.  
  340. const gXPInstallObserver = {
  341.   _findChildShell: function (aDocShell, aSoughtShell)
  342.   {
  343.     if (aDocShell == aSoughtShell)
  344.       return aDocShell;
  345.       
  346.     var node = aDocShell.QueryInterface(Components.interfaces.nsIDocShellTreeNode);
  347.     for (var i = 0; i < node.childCount; ++i) {
  348.       var docShell = node.getChildAt(i);
  349.       docShell = this._findChildShell(docShell, aSoughtShell);
  350.       if (docShell == aSoughtShell)
  351.         return docShell;
  352.     }
  353.     return null;
  354.   },
  355.   
  356.   _getBrowser: function (aDocShell) 
  357.   {
  358.     var tabbrowser = getBrowser();
  359.     for (var i = 0; i < tabbrowser.browsers.length; ++i) {
  360.       var browser = tabbrowser.getBrowserAtIndex(i);
  361.       var soughtShell = aDocShell;
  362.       var shell = this._findChildShell(browser.docShell, soughtShell);
  363.       if (shell)
  364.         return browser;
  365.     }
  366.     return null;
  367.   },
  368.  
  369.   observe: function (aSubject, aTopic, aData)
  370.   {
  371.     var brandBundle = document.getElementById("bundle_brand");
  372.     var browserBundle = document.getElementById("bundle_browser");
  373.     switch (aTopic) {
  374.     case "xpinstall-install-blocked":
  375.       var shell = aSubject.QueryInterface(Components.interfaces.nsIDocShell);
  376.       var browser = this._getBrowser(shell);
  377.       if (browser) {
  378.         var host = browser.docShell.QueryInterface(Components.interfaces.nsIWebNavigation).currentURI.host;
  379.         var brandShortName = brandBundle.getString("brandShortName");
  380.         var iconURL, messageKey, buttonKey;
  381.         if (aData == "install-chrome") {
  382.           // XXXben - use regular software install warnings for now until we can
  383.           // properly differentiate themes. It's likely in fact that themes won't
  384.           // be blocked so this code path will only be reached for extensions.
  385.           iconURL = "chrome://mozapps/skin/xpinstall/xpinstallItemGeneric.png";
  386.           messageKey = "xpinstallWarning";
  387.           buttonKey = "xpinstallWarningButton";
  388.         }
  389.         else {
  390.           iconURL = "chrome://mozapps/skin/xpinstall/xpinstallItemGeneric.png";
  391.           messageKey = "xpinstallWarning";
  392.           buttonKey = "xpinstallWarningButton";
  393.         }
  394.         
  395.         if (!gPrefService.getBoolPref("xpinstall.enabled")) {
  396.           var messageString = browserBundle.getFormattedString("xpinstallDisabledWarning", 
  397.                                                                 [brandShortName, host]);
  398.           var buttonString = browserBundle.getString("xpinstallDisabledWarningButton");
  399.           getBrowser().showMessage(browser, iconURL, messageString, buttonString, 
  400.                                    null, "xpinstall-install-edit-prefs",
  401.                                    null, "top", false);
  402.         }
  403.         else {            
  404.           var messageString = browserBundle.getFormattedString(messageKey, [brandShortName, host]);
  405.           var buttonString = browserBundle.getString(buttonKey);
  406.           var webNav = shell.QueryInterface(Components.interfaces.nsIWebNavigation);
  407.           getBrowser().showMessage(browser, iconURL, messageString, buttonString, 
  408.                                    shell, "xpinstall-install-edit-permissions",
  409.                                    null, "top", false);
  410.         }
  411.       }
  412.       break;
  413.     case "xpinstall-install-edit-prefs":
  414.       var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
  415.                          .getService(Components.interfaces.nsIWindowMediator);
  416.       var optionsWindow = wm.getMostRecentWindow("Browser:Options");
  417.       if (optionsWindow) {
  418.         optionsWindow.focus();
  419.         optionsWindow.switchPage("catFeaturesbutton");
  420.       }
  421.       else
  422.         openDialog("chrome://browser/content/pref/pref.xul", "PrefWindow",
  423.                    "chrome,titlebar,resizable,modal", "catFeaturesbutton");
  424.       var tabbrowser = getBrowser();
  425.       tabbrowser.hideMessage(tabbrowser.selectedBrowser, "top");
  426.       break;
  427.     case "xpinstall-install-edit-permissions":
  428.       var browser = this._getBrowser(aSubject.QueryInterface(Components.interfaces.nsIDocShell));
  429.       if (browser) {
  430.         var webNav = aSubject.QueryInterface(Components.interfaces.nsIWebNavigation);
  431.         var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
  432.                           .getService(Components.interfaces.nsIWindowMediator);
  433.         var existingWindow = wm.getMostRecentWindow("exceptions");
  434.         if (existingWindow) {
  435.           existingWindow.setHost(webNav.currentURI.host);
  436.           existingWindow.focus();
  437.         }
  438.         else {
  439.           var params = { blockVisible:    false,
  440.                          allowVisible:    true,
  441.                          prefilledHost:   webNav.currentURI.host,
  442.                          permissionType:  "install" };
  443.           window.openDialog("chrome://browser/content/cookieviewer/CookieExceptions.xul?permission=install",
  444.                             "_blank", "chrome,modal,resizable=yes", params);
  445.         }
  446.               
  447.         var tabbrowser = getBrowser();
  448.         tabbrowser.hideMessage(tabbrowser.selectedBrowser, "top");
  449.       }
  450.       break;
  451.     }
  452.   }
  453. };
  454.  
  455. function Startup()
  456. {
  457.   gBrowser = document.getElementById("content");
  458.  
  459.   window.tryToClose = WindowIsClosing;
  460.  
  461.   var uriToLoad = null;
  462.   // Check for window.arguments[0]. If present, use that for uriToLoad.
  463.   if ("arguments" in window && window.arguments.length >= 1 && window.arguments[0])
  464.     uriToLoad = window.arguments[0];
  465.  
  466.   try {
  467.     if (makeURL(uriToLoad).schemeIs("chrome")) {
  468.       dump("*** Preventing external load of chrome: URI into browser window\n");
  469.       dump("    Use -chrome <uri> instead\n");
  470.       window.close();
  471.       return;
  472.     }
  473.   } catch(e) {}
  474.  
  475.   gIsLoadingBlank = uriToLoad == "about:blank";
  476.  
  477.   if (!gIsLoadingBlank)
  478.     prepareForStartup();
  479.  
  480.   // only load url passed in when we're not page cycling
  481.  
  482.   if (uriToLoad && !gIsLoadingBlank) {
  483.     if ("arguments" in window && window.arguments.length >= 3)
  484.       loadURI(uriToLoad, window.arguments[2], null);
  485.     else
  486.       loadOneOrMoreURIs(uriToLoad);
  487.   }
  488.  
  489.  
  490.   var sidebarSplitter;
  491.   if (window.opener && !window.opener.closed) {
  492.     if (window.opener.gFindMode == FIND_NORMAL) {
  493.       var openerFindBar = window.opener.document.getElementById("FindToolbar");
  494.       if (openerFindBar && !openerFindBar.hidden)
  495.         openFindBar();
  496.     }
  497.       
  498.     var openerSidebarBox = window.opener.document.getElementById("sidebar-box");
  499.     // The opener can be the hidden window too, if we're coming from the state
  500.     // where no windows are open, and the hidden window has no sidebar box. 
  501.     if (openerSidebarBox && !openerSidebarBox.hidden) {
  502.       var sidebarBox = document.getElementById("sidebar-box");
  503.       var sidebarTitle = document.getElementById("sidebar-title");
  504.       sidebarTitle.setAttribute("value", window.opener.document.getElementById("sidebar-title").getAttribute("value"));
  505.       sidebarBox.setAttribute("width", openerSidebarBox.boxObject.width);
  506.       var sidebarCmd = openerSidebarBox.getAttribute("sidebarcommand");
  507.       sidebarBox.setAttribute("sidebarcommand", sidebarCmd);
  508.       sidebarBox.setAttribute("src", window.opener.document.getElementById("sidebar").getAttribute("src"));
  509.       gMustLoadSidebar = true;
  510.       sidebarBox.hidden = false;
  511.       sidebarSplitter = document.getElementById("sidebar-splitter");
  512.       sidebarSplitter.hidden = false;
  513.       document.getElementById(sidebarCmd).setAttribute("checked", "true");
  514.     }
  515.   }
  516.   else {
  517.     var box = document.getElementById("sidebar-box");
  518.     if (box.hasAttribute("sidebarcommand")) { 
  519.       var cmd = box.getAttribute("sidebarcommand");
  520.       if (cmd) {
  521.         gMustLoadSidebar = true;
  522.         box.hidden = false;
  523.         sidebarSplitter = document.getElementById("sidebar-splitter");
  524.         sidebarSplitter.hidden = false;
  525.         document.getElementById(cmd).setAttribute("checked", "true");
  526.       }
  527.     }
  528.   }
  529.  
  530.   // Certain kinds of automigration rely on this notification to complete their
  531.   // tasks BEFORE the browser window is shown.   
  532.   var obs = Components.classes["@mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService);
  533.   obs.notifyObservers(null, "browser-window-before-show", "");
  534.  
  535.   // Set a sane starting width/height for all resolutions on new profiles.
  536.   if (!document.documentElement.hasAttribute("width")) {
  537.     var defaultWidth = 994, defaultHeight;
  538.     if (screen.availHeight <= 600) {
  539.       document.documentElement.setAttribute("sizemode", "maximized");
  540.       defaultWidth = 610;
  541.       defaultHeight = 450;
  542.     }
  543.     else {
  544.       // Create a narrower window for large or wide-aspect displays, to suggest
  545.       // side-by-side page view. 
  546.       if ((screen.availWidth / 2) >= 800)
  547.         defaultWidth = (screen.availWidth / 2) - 20;
  548.       defaultHeight = screen.availHeight - 10;
  549.     }
  550.     document.documentElement.setAttribute("width", defaultWidth);
  551.     document.documentElement.setAttribute("height", defaultHeight);
  552.   }
  553.  
  554.   setTimeout(delayedStartup, 0);
  555. }
  556.  
  557. function prepareForStartup()
  558. {
  559.   gURLBar = document.getElementById("urlbar");  
  560.   gNavigatorBundle = document.getElementById("bundle_browser");
  561.   gProgressMeterPanel = document.getElementById("statusbar-progresspanel");
  562.   gBrowser.addEventListener("DOMUpdatePageReport", gPopupBlockerObserver.onUpdatePageReport, false);
  563.   gBrowser.addEventListener("DOMLinkAdded", livemarkOnLinkAdded, false);
  564.   gBrowser.addEventListener("PluginNotFound", gMissingPluginInstaller.newMissingPlugin, false);
  565.  
  566.   var webNavigation;
  567.   try {
  568.     // Create the browser instance component.
  569.     appCore = Components.classes["@mozilla.org/appshell/component/browser/instance;1"]
  570.                         .createInstance(Components.interfaces.nsIBrowserInstance);
  571.     if (!appCore)
  572.       throw "couldn't create a browser instance";
  573.  
  574.     webNavigation = getWebNavigation();
  575.     if (!webNavigation)
  576.       throw "no XBL binding for browser";
  577.   } catch (e) {
  578.     alert("Error launching browser window:" + e);
  579.     window.close(); // Give up.
  580.     return;
  581.   }
  582.  
  583.   // initialize observers and listeners
  584.   // and give C++ access to gBrowser
  585.   window.XULBrowserWindow = new nsBrowserStatusHandler();
  586.   window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
  587.         .getInterface(Components.interfaces.nsIWebNavigation)
  588.         .QueryInterface(Components.interfaces.nsIDocShellTreeItem).treeOwner
  589.         .QueryInterface(Components.interfaces.nsIInterfaceRequestor)
  590.         .getInterface(Components.interfaces.nsIXULWindow)
  591.         .XULBrowserWindow = window.XULBrowserWindow;
  592.   gBrowser.docShell
  593.           .QueryInterface(nsCI.nsIDocShellTreeItem)
  594.           .rootTreeItem
  595.           .QueryInterface(nsCI.nsIInterfaceRequestor)
  596.           .getInterface(nsCI.nsIDOMWindow)
  597.           .QueryInterface(nsCI.nsIInterfaceRequestor)
  598.           .getInterface(nsCI.nsIDOMWindowUtils)
  599.           .browserDOMWindow = new nsBrowserAccess();
  600.  
  601.   window.browserContentListener =
  602.     new nsBrowserContentListener(window, gBrowser);
  603.  
  604.   // set default character set if provided
  605.   if ("arguments" in window && window.arguments.length > 1 && window.arguments[1]) {
  606.     if (window.arguments[1].indexOf("charset=") != -1) {
  607.       var arrayArgComponents = window.arguments[1].split("=");
  608.       if (arrayArgComponents) {
  609.         //we should "inherit" the charset menu setting in a new window
  610.         getMarkupDocumentViewer().defaultCharacterSet = arrayArgComponents[1];
  611.       }
  612.     }
  613.   }
  614.  
  615.   // Initialize browser instance..
  616.   appCore.setWebShellWindow(window);
  617.  
  618.   // Wire up session and global history before any possible
  619.   // progress notifications for back/forward button updating
  620.   webNavigation.sessionHistory = Components.classes["@mozilla.org/browser/shistory;1"]
  621.                                            .createInstance(Components.interfaces.nsISHistory);
  622.  
  623.   // enable global history
  624.   gBrowser.docShell.QueryInterface(Components.interfaces.nsIDocShellHistory).useGlobalHistory = true;
  625.  
  626.   const selectedBrowser = gBrowser.selectedBrowser;
  627.   if (selectedBrowser.securityUI)
  628.     selectedBrowser.securityUI.init(selectedBrowser.contentWindow);
  629.  
  630.   // hook up UI through progress listener
  631.   gBrowser.addProgressListener(window.XULBrowserWindow, Components.interfaces.nsIWebProgress.NOTIFY_ALL);
  632. }
  633.  
  634. function delayedStartup()
  635. {
  636.   var os = Components.classes["@mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService);
  637.   os.addObserver(gSessionHistoryObserver, "browser:purge-session-history", false);
  638.   
  639.   // We have to do this because we manually hook up history for the first browser in prepareForStartup
  640.   os.addObserver(gBrowser.browsers[0], "browser:purge-session-history", false);
  641.   os.addObserver(gXPInstallObserver, "xpinstall-install-blocked", false);
  642.   os.addObserver(gXPInstallObserver, "xpinstall-install-edit-prefs", false);
  643.   os.addObserver(gXPInstallObserver, "xpinstall-install-edit-permissions", false);
  644.   os.addObserver(gMissingPluginInstaller, "missing-plugin", false);
  645.  
  646.   gPrefService = Components.classes["@mozilla.org/preferences-service;1"]
  647.                            .getService(Components.interfaces.nsIPrefBranch);
  648.   BrowserOffline.init();
  649.   
  650.   if (gURLBar && document.documentElement.getAttribute("chromehidden").indexOf("toolbar") != -1) {
  651.     gURLBar.setAttribute("readonly", "true"); 
  652.     gURLBar.setAttribute("enablehistory", "false");
  653.   }
  654.  
  655.   if (gIsLoadingBlank)
  656.     prepareForStartup();
  657.  
  658.   if (gURLBar)
  659.     gURLBar.addEventListener("dragdrop", URLBarOnDrop, true);
  660.  
  661.   // loads the services
  662.   initServices();
  663.   initBMService();
  664.   gBrowser.addEventListener("load", function(evt) { setTimeout(loadEventHandlers, 0, evt); }, true);
  665.  
  666.   window.addEventListener("keypress", ctrlNumberTabSelection, false);
  667.  
  668.   if (gMustLoadSidebar) {
  669.     var sidebar = document.getElementById("sidebar");
  670.     var sidebarBox = document.getElementById("sidebar-box");
  671.     sidebar.setAttribute("src", sidebarBox.getAttribute("src"));
  672.   }
  673.   
  674.   initFindBar();
  675.  
  676.   // now load bookmarks
  677.   BMSVC.readBookmarks();  
  678.   var bt = document.getElementById("bookmarks-ptf");
  679.   if (bt) {
  680.     var btf = BMSVC.getBookmarksToolbarFolder().Value;
  681.     bt.ref = btf;
  682.     document.getElementById("bookmarks-chevron").ref = btf;
  683.     bt.database.AddObserver(BookmarksToolbarRDFObserver);
  684.     bt.controllers.appendController(BookmarksMenuController);
  685.   }
  686.   var bm = document.getElementById("bookmarks-menu");
  687.   bm.controllers.appendController(BookmarksMenuController);
  688.   window.addEventListener("resize", BookmarksToolbar.resizeFunc, false);
  689.  
  690.   // called when we go into full screen, even if it is 
  691.   // initiated by a web page script
  692.   window.addEventListener("fullscreen", onFullScreen, false);
  693.  
  694.   var element;
  695.   if (gIsLoadingBlank && gURLBar && !gURLBar.hidden && !gURLBar.parentNode.parentNode.collapsed)
  696.     element = gURLBar;
  697.   else
  698.     element = _content;
  699.  
  700.   // This is a redo of the fix for jag bug 91884
  701.   var ww = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
  702.                      .getService(Components.interfaces.nsIWindowWatcher);
  703.   if (window == ww.activeWindow) {
  704.     element.focus();
  705.   } else {
  706.     // set the element in command dispatcher so focus will restore properly
  707.     // when the window does become active
  708.     if (element instanceof Components.interfaces.nsIDOMWindow) {
  709.       document.commandDispatcher.focusedWindow = element;
  710.       document.commandDispatcher.focusedElement = null;
  711.     } else if (element instanceof Components.interfaces.nsIDOMElement) {
  712.       document.commandDispatcher.focusedWindow = element.ownerDocument.defaultView;
  713.       document.commandDispatcher.focusedElement = element;
  714.     }
  715.   }
  716.  
  717.   SetPageProxyState("invalid", null);
  718.  
  719.   var toolbox = document.getElementById("navigator-toolbox");
  720.   toolbox.customizeDone = BrowserToolboxCustomizeDone;
  721.  
  722.   // Enable/Disable Form Fill
  723.   gFormFillPrefListener = new FormFillPrefListener();
  724.   var pbi = gPrefService.QueryInterface(Components.interfaces.nsIPrefBranchInternal);
  725.   pbi.addObserver(gFormFillPrefListener.domain, gFormFillPrefListener, false);
  726.   gFormFillPrefListener.toggleFormFill();
  727.  
  728.   // Enable/Disable URL Bar Auto Fill
  729.   gURLBarAutoFillPrefListener = new URLBarAutoFillPrefListener();
  730.   pbi.addObserver(gURLBarAutoFillPrefListener.domain, gURLBarAutoFillPrefListener, false);
  731.  
  732.   pbi.addObserver(gHomeButton.prefDomain, gHomeButton, false);
  733.   gHomeButton.updateTooltip();
  734.   
  735.   // Initialize Plugin Overrides
  736.   const kOverridePref = "browser.download.pluginOverrideTypes";
  737.   if (gPrefService.prefHasUserValue(kOverridePref)) {
  738.     var types = gPrefService.getCharPref(kOverridePref);
  739.     types = types.split(",");
  740.     
  741.     const kPluginOverrideTypesNotHandled = "browser.download.pluginOverrideTypesNotHandled";
  742.     
  743.     var catman = Components.classes["@mozilla.org/categorymanager;1"].getService(Components.interfaces.nsICategoryManager);
  744.     var typesNotHandled = "";
  745.     for (var i = 0; i < types.length; ++i) {
  746.       // Keep track of all overrides for plugins that aren't actually installed,
  747.       // so we know not to show them in the plugin configuration dialog BUT 
  748.       // don't delete the overrides such that when the user actually installs the 
  749.       // plugin in this build their preferences are remembered.
  750.       try {
  751.         var catEntry = catman.getCategoryEntry("Gecko-Content-Viewers", types[i]);
  752.       }
  753.       catch (e) {
  754.         catEntry = "";
  755.       }
  756.       if (catEntry == "")
  757.         typesNotHandled += types[i] + ",";
  758.     
  759.       catman.deleteCategoryEntry("Gecko-Content-Viewers", types[i], false);
  760.     }
  761.     
  762.     if (typesNotHandled) {
  763.       typesNotHandled = typesNotHandled.substr(0, typesNotHandled.length - 1);
  764.       gPrefService.setCharPref(kPluginOverrideTypesNotHandled, typesNotHandled);
  765.     }
  766.     else if (gPrefService.prefHasUserValue(kPluginOverrideTypesNotHandled))
  767.       gPrefService.clearUserPref(kPluginOverrideTypesNotHandled);
  768.   }
  769.  
  770.   gClickSelectsAll = gPrefService.getBoolPref("browser.urlbar.clickSelectsAll");
  771.  
  772.   clearObsoletePrefs();
  773.  
  774.   // Perform default browser checking (after window opens).
  775.   var shell = getShellService();
  776.   if (shell) {
  777.     var shouldCheck = shell.shouldCheckDefaultBrowser;
  778.     if (shouldCheck && !shell.isDefaultBrowser(true)) {
  779.       var brandBundle = document.getElementById("bundle_brand");
  780.       var shellBundle = document.getElementById("bundle_shell");
  781.  
  782.       var brandShortName = brandBundle.getString("brandShortName");
  783.       var promptTitle = shellBundle.getString("setDefaultBrowserTitle");
  784.       var promptMessage = shellBundle.getFormattedString("setDefaultBrowserMessage", 
  785.                                                          [brandShortName]);
  786.       var checkboxLabel = shellBundle.getFormattedString("setDefaultBrowserDontAsk",
  787.                                                          [brandShortName]);
  788.       const IPS = Components.interfaces.nsIPromptService;
  789.       var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
  790.                                                 .getService(IPS);
  791.       var checkEveryTime = { value: shouldCheck };
  792.       var rv = ps.confirmEx(window, promptTitle, promptMessage, 
  793.                             (IPS.BUTTON_TITLE_YES * IPS.BUTTON_POS_0) + 
  794.                             (IPS.BUTTON_TITLE_NO * IPS.BUTTON_POS_1),
  795.                             null, null, null, checkboxLabel, checkEveryTime);
  796.       if (rv == 0)
  797.         shell.setDefaultBrowser(true, false);
  798.       shell.shouldCheckDefaultBrowser = checkEveryTime.value;
  799.     }
  800.   } else {
  801.     // We couldn't get the shell service; go hide the mail toolbar button.
  802.     var mailbutton = document.getElementById("mail-button");
  803.     if (mailbutton)
  804.       mailbutton.hidden = true;
  805.   }
  806.  
  807.   var updatePanel = document.getElementById("softwareupdate");
  808.   try {
  809.     updatePanel.init();
  810.   }
  811.   catch (e) { }
  812.  
  813.   // BiDi UI
  814.   if (isBidiEnabled()) {
  815.     document.getElementById("documentDirection-separator").hidden = false;
  816.     document.getElementById("documentDirection-swap").hidden = false;
  817.     document.getElementById("textfieldDirection-separator").hidden = false;
  818.     document.getElementById("textfieldDirection-swap").hidden = false;
  819.   }
  820.  
  821.   // Ensure the Software Update item is visible on the menubar on Windows and 
  822.   // Linux, and on the navigation toolbar on MacOSX (since we can't put items on
  823.   // the menubar on OS X)... if the Throbber is present place the Updates item
  824.   // to the left of it, otherwise place it at the end of the bar. 
  825.   // We don't use a customizable item for the updates item so we can always be
  826.   // sure it's present.
  827.   var updateItem = document.getElementById("softwareupdate-item");
  828.   updateItem.parentNode.removeChild(updateItem);
  829.   var theToolbar = document.getElementById("toolbar-menubar");
  830.   if (theToolbar.lastChild.id == "throbber-box")
  831.     theToolbar.insertBefore(updateItem, document.getElementById("throbber-box"));
  832.   else
  833.     theToolbar.appendChild(updateItem);
  834. }
  835.  
  836. function Shutdown()
  837. {
  838.   var os = Components.classes["@mozilla.org/observer-service;1"]
  839.     .getService(Components.interfaces.nsIObserverService);
  840.   os.removeObserver(gSessionHistoryObserver, "browser:purge-session-history");
  841.   os.removeObserver(gBrowser.browsers[0], "browser:purge-session-history");
  842.   os.removeObserver(gXPInstallObserver, "xpinstall-install-blocked");
  843.   os.removeObserver(gXPInstallObserver, "xpinstall-install-edit-permissions");
  844.   os.removeObserver(gXPInstallObserver, "xpinstall-install-edit-prefs");
  845.   os.removeObserver(gMissingPluginInstaller, "missing-plugin");
  846.  
  847.   try {
  848.     gBrowser.removeProgressListener(window.XULBrowserWindow);
  849.   } catch (ex) {
  850.   }
  851.  
  852.   var bt = document.getElementById("bookmarks-ptf");
  853.   if (bt) {
  854.     try {
  855.       bt.database.RemoveObserver(BookmarksToolbarRDFObserver);
  856.       bt.controllers.removeController(BookmarksMenuController);
  857.     } catch (ex) {
  858.     }
  859.   }
  860.  
  861.   try {
  862.     var bm = document.getElementById("bookmarks-menu");
  863.     bm.controllers.removeController(BookmarksMenuController);
  864.   } catch (ex) {
  865.   }
  866.  
  867.   try {
  868.     var pbi = gPrefService.QueryInterface(Components.interfaces.nsIPrefBranchInternal);
  869.     pbi.removeObserver(gFormFillPrefListener.domain, gFormFillPrefListener);
  870.     pbi.removeObserver(gURLBarAutoFillPrefListener.domain, gURLBarAutoFillPrefListener);
  871.     pbi.removeObserver(gHomeButton.prefDomain, gHomeButton);
  872.   } catch (ex) {
  873.   }
  874.  
  875.   BrowserOffline.uninit();
  876.   
  877.   uninitFindBar();
  878.  
  879.   var windowManager = Components.classes['@mozilla.org/appshell/window-mediator;1'].getService();
  880.   var windowManagerInterface = windowManager.QueryInterface(Components.interfaces.nsIWindowMediator);
  881.   var enumerator = windowManagerInterface.getEnumerator(null);
  882.   enumerator.getNext();
  883.   if (!enumerator.hasMoreElements()) {
  884.     document.persist("sidebar-box", "sidebarcommand");
  885.     document.persist("sidebar-box", "width");
  886.     document.persist("sidebar-box", "src");
  887.     document.persist("sidebar-title", "value");
  888.   }
  889.  
  890.   window.XULBrowserWindow.destroy();
  891.   window.XULBrowserWindow = null;
  892.   window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
  893.         .getInterface(Components.interfaces.nsIWebNavigation)
  894.         .QueryInterface(Components.interfaces.nsIDocShellTreeItem).treeOwner
  895.         .QueryInterface(Components.interfaces.nsIInterfaceRequestor)
  896.         .getInterface(Components.interfaces.nsIXULWindow)
  897.         .XULBrowserWindow = null;
  898.   gBrowser.docShell
  899.           .QueryInterface(nsCI.nsIDocShellTreeItem)
  900.           .rootTreeItem
  901.           .QueryInterface(nsCI.nsIInterfaceRequestor)
  902.           .getInterface(nsCI.nsIDOMWindow)
  903.           .QueryInterface(nsCI.nsIInterfaceRequestor)
  904.           .getInterface(nsCI.nsIDOMWindowUtils)
  905.           .browserDOMWindow = null;
  906.  
  907.   window.browserContentListener.close();
  908.   // Close the app core.
  909.   if (appCore)
  910.     appCore.close();
  911. }
  912.  
  913. function FormFillPrefListener()
  914. {
  915.   gBrowser.attachFormFill();
  916. }
  917.  
  918. FormFillPrefListener.prototype =
  919. {
  920.   domain: "browser.formfill.enable",
  921.   observe: function (aSubject, aTopic, aPrefName)
  922.   {
  923.     if (aTopic != "nsPref:changed" || aPrefName != this.domain)
  924.       return;
  925.       
  926.     this.toggleFormFill();
  927.   },
  928.   
  929.   toggleFormFill: function ()
  930.   {
  931.     try {
  932.       gFormFillEnabled = gPrefService.getBoolPref(this.domain);
  933.     }
  934.     catch (e) {
  935.     }
  936.     var formController = Components.classes["@mozilla.org/satchel/form-fill-controller;1"].getService(Components.interfaces.nsIAutoCompleteInput);
  937.     formController.disableAutoComplete = !gFormFillEnabled;
  938.  
  939.     var searchBar = document.getElementsByTagName("searchbar");
  940.     for (var i=0; i<searchBar.length;i++) {
  941.       if (gFormFillEnabled)
  942.         searchBar[i].removeAttribute("disableautocomplete");
  943.       else
  944.         searchBar[i].setAttribute("disableautocomplete", "true");
  945.     }
  946.   }
  947. }
  948.  
  949. function URLBarAutoFillPrefListener()
  950. {
  951.   this.toggleAutoFillInURLBar();
  952. }
  953.  
  954. URLBarAutoFillPrefListener.prototype =
  955. {
  956.   domain: "browser.urlbar.autoFill",
  957.   observe: function (aSubject, aTopic, aPrefName)
  958.   {
  959.     if (aTopic != "nsPref:changed" || aPrefName != this.domain)
  960.       return;
  961.       
  962.     this.toggleAutoFillInURLBar();
  963.   },
  964.   
  965.   toggleAutoFillInURLBar: function ()
  966.   {
  967.     if (!gURLBar)
  968.       return;
  969.  
  970.     var prefValue = false;
  971.     try {
  972.       prefValue = gPrefService.getBoolPref(this.domain);
  973.     }
  974.     catch (e) {
  975.     }
  976.  
  977.     if (prefValue)
  978.       gURLBar.setAttribute("completedefaultindex", "true");
  979.     else
  980.       gURLBar.removeAttribute("completedefaultindex");
  981.   }
  982. }
  983.  
  984. function ctrlNumberTabSelection(event)
  985. {  
  986.   if (event.altKey && event.keyCode == KeyEvent.DOM_VK_RETURN) {    
  987.     // XXXblake Proper fix is to just check whether focus is in the urlbar. However, focus with the autocomplete widget is all
  988.     // hacky and broken and there's no way to do that right now. So this just patches it to ensure that alt+enter works when focus
  989.     // is on a link.
  990.     if (!(document.commandDispatcher.focusedElement instanceof HTMLAnchorElement)) {
  991.       // Don't let winxp beep on ALT+ENTER, since the URL bar uses it.
  992.       event.preventDefault();
  993.       return;
  994.     }
  995.   }
  996.  
  997.   if (!event.ctrlKey)
  998.     return;
  999.  
  1000.   var index = event.charCode - 49;
  1001.   if (index < 0 || index > 8)
  1002.     return;
  1003.  
  1004.   if (index >= gBrowser.tabContainer.childNodes.length)
  1005.     return;
  1006.  
  1007.   var oldTab = gBrowser.selectedTab;
  1008.   var newTab = gBrowser.tabContainer.childNodes[index];
  1009.   if (newTab != oldTab) {
  1010.     oldTab.selected = false;
  1011.     gBrowser.selectedTab = newTab;
  1012.   }
  1013.  
  1014.   event.preventDefault();
  1015.   event.preventBubble();
  1016.   event.preventCapture();
  1017.   event.stopPropagation();
  1018. }
  1019.  
  1020. function gotoHistoryIndex(aEvent)
  1021. {
  1022.   var index = aEvent.target.getAttribute("index");
  1023.   if (!index)
  1024.     return false;
  1025.  
  1026.   var where = whereToOpenLink(aEvent);
  1027.  
  1028.   if (where == "current") {
  1029.     // Normal click.  Go there in the current tab and update session history.
  1030.  
  1031.     try {
  1032.       getWebNavigation().gotoIndex(index);
  1033.     }
  1034.     catch(ex) {
  1035.       return false;
  1036.     }
  1037.     return true;
  1038.   }
  1039.   else {
  1040.     // Modified click.  Go there in a new tab/window.
  1041.     // This code doesn't copy history or work well with framed pages.
  1042.     
  1043.     var sessionHistory = getWebNavigation().sessionHistory;
  1044.     var entry = sessionHistory.getEntryAtIndex(index, false);
  1045.     var url = entry.URI.spec;
  1046.     openUILinkIn(url, where);
  1047.     return true;
  1048.   }
  1049. }
  1050.  
  1051. function BrowserForward(aEvent, aIgnoreAlt)
  1052. {
  1053.   var where = whereToOpenLink(aEvent, false, aIgnoreAlt);
  1054.  
  1055.   if (where == "current") {
  1056.     try {
  1057.       getWebNavigation().goForward();
  1058.     }
  1059.     catch(ex) {
  1060.     }
  1061.   }
  1062.   else {
  1063.     var sessionHistory = getWebNavigation().sessionHistory;
  1064.     var currentIndex = sessionHistory.index;
  1065.     var entry = sessionHistory.getEntryAtIndex(currentIndex + 1, false);
  1066.     var url = entry.URI.spec;
  1067.     openUILinkIn(url, where);
  1068.   }
  1069. }
  1070.  
  1071. function BrowserBack(aEvent, aIgnoreAlt)
  1072. {
  1073.   var where = whereToOpenLink(aEvent, false, aIgnoreAlt);
  1074.  
  1075.   if (where == "current") {
  1076.     try {
  1077.       getWebNavigation().goBack();
  1078.     }
  1079.     catch(ex) {
  1080.     }
  1081.   }
  1082.   else {
  1083.     var sessionHistory = getWebNavigation().sessionHistory;
  1084.     var currentIndex = sessionHistory.index;
  1085.     var entry = sessionHistory.getEntryAtIndex(currentIndex - 1, false);
  1086.     var url = entry.URI.spec;
  1087.     openUILinkIn(url, where);
  1088.   }
  1089. }
  1090.  
  1091. function BrowserHandleBackspace()
  1092. {
  1093.   BrowserBack();
  1094. }
  1095.  
  1096. function BrowserBackMenu(event)
  1097. {
  1098.   return FillHistoryMenu(event.target, "back");
  1099. }
  1100.  
  1101. function BrowserForwardMenu(event)
  1102. {
  1103.   return FillHistoryMenu(event.target, "forward");
  1104. }
  1105.  
  1106. function BrowserStop()
  1107. {
  1108.   try {
  1109.     const stopFlags = nsIWebNavigation.STOP_ALL;
  1110.     getWebNavigation().stop(stopFlags);
  1111.   }
  1112.   catch(ex) {
  1113.   }
  1114. }
  1115.  
  1116. function BrowserReload()
  1117. {
  1118.   const reloadFlags = nsIWebNavigation.LOAD_FLAGS_NONE;
  1119.   return BrowserReloadWithFlags(reloadFlags);
  1120. }
  1121.  
  1122. function BrowserReloadSkipCache()
  1123. {
  1124.   // Bypass proxy and cache.
  1125.   const reloadFlags = nsIWebNavigation.LOAD_FLAGS_BYPASS_PROXY | nsIWebNavigation.LOAD_FLAGS_BYPASS_CACHE;
  1126.   return BrowserReloadWithFlags(reloadFlags);
  1127. }
  1128.  
  1129. function BrowserHome()
  1130. {
  1131.   var homePage = gHomeButton.getHomePage();
  1132.   loadOneOrMoreURIs(homePage);
  1133. }
  1134.  
  1135. function BrowserHomeClick(aEvent)
  1136. {
  1137.   if (aEvent.button == 2) // right-click: do nothing
  1138.     return;
  1139.  
  1140.   var homePage = gHomeButton.getHomePage();
  1141.   var where = whereToOpenLink(aEvent);
  1142.   var urls;
  1143.  
  1144.   // openUILinkIn in utilityOverlay.js doesn't handle loading multiple pages
  1145.   switch (where) {
  1146.   case "save":
  1147.     urls = homePage.split("|");
  1148.     saveURL(urls[0], null, null, true);  // only save the first page
  1149.     break;
  1150.   case "current":
  1151.     loadOneOrMoreURIs(homePage);
  1152.     break;
  1153.   case "tabshifted":
  1154.   case "tab":
  1155.     urls = homePage.split("|");
  1156.     var firstTabAdded = gBrowser.addTab(urls[0]);
  1157.     for (var i = 1; i < urls.length; ++i)
  1158.       gBrowser.addTab(urls[i]);
  1159.     if ((where == "tab") ^ getBoolPref("browser.tabs.loadBookmarksInBackground", false)) {
  1160.       gBrowser.selectedTab = firstTabAdded;
  1161.       _content.focus();
  1162.     }
  1163.     break;
  1164.   case "window":
  1165.     OpenBrowserWindow();
  1166.     break;
  1167.   }
  1168. }
  1169.  
  1170. function loadOneOrMoreURIs(aURIString)
  1171. {
  1172.   var urls = aURIString.split("|");
  1173.   loadURI(urls[0]);
  1174.   for (var i = 1; i < urls.length; ++i)
  1175.     gBrowser.addTab(urls[i]);
  1176. }
  1177.  
  1178. function constructGoMenuItem(goMenu, beforeItem, url, title)
  1179. {
  1180.   var menuitem = document.createElementNS(kXULNS, "menuitem");
  1181.   menuitem.setAttribute("statustext", url);
  1182.   menuitem.setAttribute("label", title);
  1183.   goMenu.insertBefore(menuitem, beforeItem);
  1184.   return menuitem;
  1185. }
  1186.  
  1187. function onGoMenuHidden()
  1188. {
  1189.   setTimeout(destroyGoMenuItems, 0, document.getElementById('goPopup'));
  1190. }
  1191.  
  1192. function destroyGoMenuItems(goMenu) {
  1193.   var startSeparator = document.getElementById("startHistorySeparator");
  1194.   var endSeparator = document.getElementById("endHistorySeparator");
  1195.   endSeparator.hidden = true;
  1196.  
  1197.   // Destroy the items.
  1198.   var destroy = false;
  1199.   for (var i = 0; i < goMenu.childNodes.length; i++) {
  1200.     var item = goMenu.childNodes[i];
  1201.     if (item == endSeparator)
  1202.       break;
  1203.  
  1204.     if (destroy) {
  1205.       i--;
  1206.       goMenu.removeChild(item);
  1207.     }
  1208.  
  1209.     if (item == startSeparator)
  1210.       destroy = true;
  1211.   }
  1212. }
  1213.  
  1214. function updateGoMenu(goMenu)
  1215. {
  1216.   // In case the timer didn't fire.
  1217.   destroyGoMenuItems(goMenu);
  1218.  
  1219.   var history = document.getElementById("hiddenHistoryTree");
  1220.   
  1221.   if (history.hidden) {
  1222.     history.hidden = false;
  1223.     var globalHistory = Components.classes["@mozilla.org/browser/global-history;2"]
  1224.                                   .getService(Components.interfaces.nsIRDFDataSource);
  1225.     history.database.AddDataSource(globalHistory);
  1226.   }
  1227.  
  1228.   if (!history.ref)
  1229.     history.ref = "NC:HistoryRoot";
  1230.   
  1231.   var count = history.treeBoxObject.view.rowCount;
  1232.   if (count > 10)
  1233.     count = 10;
  1234.  
  1235.   if (count == 0)
  1236.     return;
  1237.  
  1238.   const NC_NS     = "http://home.netscape.com/NC-rdf#";
  1239.  
  1240.   if (!gRDF)
  1241.      gRDF = Components.classes["@mozilla.org/rdf/rdf-service;1"]
  1242.                       .getService(Components.interfaces.nsIRDFService);
  1243.  
  1244.   var builder = history.builder.QueryInterface(Components.interfaces.nsIXULTreeBuilder);
  1245.   
  1246.   var beforeItem = document.getElementById("endHistorySeparator");
  1247.   
  1248.   var nameResource = gRDF.GetResource(NC_NS + "Name");
  1249.  
  1250.   var endSep = beforeItem;
  1251.   var showSep = false;
  1252.  
  1253.   for (var i = count-1; i >= 0; i--) {
  1254.     var res = builder.getResourceAtIndex(i);
  1255.     var url = res.Value;
  1256.     var titleRes = history.database.GetTarget(res, nameResource, true);
  1257.     if (!titleRes)
  1258.       continue;
  1259.  
  1260.     showSep = true;
  1261.     var titleLiteral = titleRes.QueryInterface(Components.interfaces.nsIRDFLiteral);
  1262.     beforeItem = constructGoMenuItem(goMenu, beforeItem, url, titleLiteral.Value);
  1263.   }
  1264.  
  1265.   if (showSep)
  1266.     endSep.hidden = false;
  1267. }
  1268.  
  1269. function addBookmarkAs(aBrowser, aIsWebPanel)
  1270. {
  1271.   const browsers = aBrowser.browsers;
  1272.   if (browsers && browsers.length > 1)
  1273.     addBookmarkForTabBrowser(aBrowser);
  1274.   else
  1275.     addBookmarkForBrowser(aBrowser.webNavigation, aIsWebPanel);
  1276. }
  1277.  
  1278. function addBookmarkForTabBrowser(aTabBrowser, aSelect)
  1279. {
  1280.   var tabsInfo = [];
  1281.   var currentTabInfo = { name: "", url: "", charset: null };
  1282.  
  1283.   const activeBrowser = aTabBrowser.selectedBrowser;
  1284.   const browsers = aTabBrowser.browsers;
  1285.   for (var i = 0; i < browsers.length; ++i) {
  1286.     var webNav = browsers[i].webNavigation;
  1287.     var url = webNav.currentURI.spec;
  1288.     var name = "";
  1289.     var charSet;
  1290.     try {
  1291.       var doc = webNav.document;
  1292.       name = doc.title || url;
  1293.       charSet = doc.characterSet;
  1294.     } catch (e) {
  1295.       name = url;
  1296.     }
  1297.     tabsInfo[i] = { name: name, url: url, charset: charSet };
  1298.     if (browsers[i] == activeBrowser)
  1299.       currentTabInfo = tabsInfo[i];
  1300.   }
  1301.   openDialog("chrome://browser/content/bookmarks/addBookmark2.xul", "",
  1302.              "centerscreen,chrome,dialog,resizable,dependent",
  1303.              currentTabInfo.name, currentTabInfo.url, null,
  1304.              currentTabInfo.charset, "addGroup" + (aSelect ? ",group" : ""), tabsInfo);
  1305. }
  1306.  
  1307. function addBookmarkForBrowser(aDocShell, aIsWebPanel)
  1308. {
  1309.   // Bug 52536: We obtain the URL and title from the nsIWebNavigation
  1310.   // associated with a <browser/> rather than from a DOMWindow.
  1311.   // This is because when a full page plugin is loaded, there is
  1312.   // no DOMWindow (?) but information about the loaded document
  1313.   // may still be obtained from the webNavigation. 
  1314.   var url = aDocShell.currentURI.spec;
  1315.   var title, charSet = null;
  1316.   try {
  1317.     title = aDocShell.document.title || url;
  1318.     charSet = aDocShell.document.characterSet;
  1319.   }
  1320.   catch (e) {
  1321.     title = url;
  1322.   }
  1323.   BookmarksUtils.addBookmark(url, title, charSet, aIsWebPanel);
  1324. }
  1325.  
  1326. function openLocation()
  1327. {
  1328.   if (gURLBar && !gURLBar.parentNode.parentNode.collapsed) {
  1329.     gURLBar.focus();
  1330.     gURLBar.select();
  1331.   }
  1332.   else {
  1333.       openDialog("chrome://browser/content/openLocation.xul", "_blank", "chrome,modal,titlebar", window);
  1334.   }
  1335. }
  1336.  
  1337. function BrowserOpenTab()
  1338. {
  1339.   gBrowser.selectedTab = gBrowser.addTab('about:blank');
  1340.   if (gURLBar)
  1341.     setTimeout(function() { gURLBar.focus(); }, 0);
  1342. }
  1343.  
  1344. /* Called from the openLocation dialog. This allows that dialog to instruct
  1345.    its opener to open a new window and then step completely out of the way.
  1346.    Anything less byzantine is causing horrible crashes, rather believably,
  1347.    though oddly only on Linux. */
  1348. function delayedOpenWindow(chrome,flags,url)
  1349. {
  1350.   // The other way to use setTimeout,
  1351.   // setTimeout(openDialog, 10, chrome, "_blank", flags, url),
  1352.   // doesn't work here.  The extra "magic" extra argument setTimeout adds to
  1353.   // the callback function would confuse prepareForStartup() by making
  1354.   // window.arguments[1] be an integer instead of null.
  1355.   setTimeout(function() { openDialog(chrome, "_blank", flags, url); }, 10);
  1356. }
  1357.  
  1358. /* Required because the tab needs time to set up its content viewers and get the load of
  1359.    the URI kicked off before becoming the active content area. */
  1360. function delayedOpenTab(url)
  1361. {
  1362.   setTimeout(function(aTabElt) { gBrowser.selectedTab = aTabElt; }, 0, gBrowser.addTab(url));
  1363. }
  1364.  
  1365. function BrowserOpenFileWindow()
  1366. {
  1367.   // Get filepicker component.
  1368.   try {
  1369.     const nsIFilePicker = Components.interfaces.nsIFilePicker;
  1370.     var fp = Components.classes["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);
  1371.     fp.init(window, gNavigatorBundle.getString("openFile"), nsIFilePicker.modeOpen);
  1372.     fp.appendFilters(nsIFilePicker.filterAll | nsIFilePicker.filterText | nsIFilePicker.filterImages |
  1373.                      nsIFilePicker.filterXML | nsIFilePicker.filterHTML);
  1374.  
  1375.     if (fp.show() == nsIFilePicker.returnOK)
  1376.       openTopWin(fp.fileURL.spec);
  1377.   } catch (ex) {
  1378.   }
  1379. }
  1380.  
  1381. function BrowserCloseTabOrWindow()
  1382. {
  1383.   if (gBrowser.localName == 'tabbrowser' && gBrowser.tabContainer.childNodes.length > 1) {
  1384.     // Just close up a tab.
  1385.     gBrowser.removeCurrentTab();
  1386.     return;
  1387.   }
  1388.  
  1389.   BrowserCloseWindow();
  1390. }
  1391.  
  1392. function BrowserTryToCloseWindow()
  1393. {
  1394.   //give tryToClose a chance to veto if it is defined
  1395.   if (typeof(window.tryToClose) != "function" || window.tryToClose())
  1396.     BrowserCloseWindow();
  1397. }
  1398.  
  1399. function BrowserCloseWindow() 
  1400. {
  1401.   // This code replicates stuff in Shutdown().  It is here because
  1402.   // window.screenX and window.screenY have real values.  We need
  1403.   // to fix this eventually but by replicating the code here, we
  1404.   // provide a means of saving position (it just requires that the
  1405.   // user close the window via File->Close (vs. close box).
  1406.   
  1407.   // Get the current window position/size.
  1408.   var x = window.screenX;
  1409.   var y = window.screenY;
  1410.   var h = window.outerHeight;
  1411.   var w = window.outerWidth;
  1412.  
  1413.   // Store these into the window attributes (for persistence).
  1414.   var win = document.getElementById( "main-window" );
  1415.   win.setAttribute( "x", x );
  1416.   win.setAttribute( "y", y );
  1417.   win.setAttribute( "height", h );
  1418.   win.setAttribute( "width", w );
  1419.  
  1420.   closeWindow(true);
  1421. }
  1422.  
  1423. function loadURI(uri, referrer, postData)
  1424. {
  1425.   try {
  1426.     if (postData === undefined)
  1427.       postData = null;
  1428.     getWebNavigation().loadURI(uri, nsIWebNavigation.LOAD_FLAGS_NONE, referrer, postData, null);
  1429.   } catch (e) {
  1430.   }
  1431. }
  1432.  
  1433. function BrowserLoadURL(aTriggeringEvent, aPostData)
  1434. {
  1435.   var url = gURLBar.value;
  1436.   if (url.match(/^view-source:/)) {
  1437.     BrowserViewSourceOfURL(url.replace(/^view-source:/, ""), null, null);
  1438.   } else {
  1439.     if (gBrowser.localName == "tabbrowser" &&
  1440.         aTriggeringEvent && 'altKey' in aTriggeringEvent &&
  1441.         aTriggeringEvent.altKey) {
  1442.       _content.focus();
  1443.       var t = gBrowser.addTab(url, null, null, aPostData); // open link in new tab
  1444.       gBrowser.selectedTab = t;
  1445.       gURLBar.value = url;
  1446.       event.preventDefault();
  1447.       event.preventBubble();
  1448.       event.preventCapture();
  1449.       event.stopPropagation();
  1450.     }
  1451.     else  
  1452.       loadURI(url, null, aPostData);
  1453.     _content.focus();
  1454.   }
  1455. }
  1456.  
  1457. function SearchLoadURL(aURL, aTriggeringEvent)
  1458. {
  1459.   if (gBrowser.localName == "tabbrowser" &&
  1460.       aTriggeringEvent && 'altKey' in aTriggeringEvent &&
  1461.       aTriggeringEvent.altKey) {
  1462.     _content.focus();
  1463.     var t = gBrowser.addTab(aURL, null); // open link in new tab
  1464.     gBrowser.selectedTab = t;
  1465.     if (gURLBar)
  1466.       gURLBar.value = aURL;
  1467.   }
  1468.   else  
  1469.     loadURI(aURL, null, null);
  1470.   _content.focus();
  1471. }
  1472.  
  1473. function getShortcutOrURI(aURL, aPostDataRef)
  1474. {
  1475.   // rjc: added support for URL shortcuts (3/30/1999)
  1476.   try {
  1477.     var shortcutURL = BMSVC.resolveKeyword(aURL, aPostDataRef);
  1478.     if (!shortcutURL) {
  1479.       // rjc: add support for string substitution with shortcuts (4/4/2000)
  1480.       //      (see bug # 29871 for details)
  1481.       var aOffset = aURL.indexOf(" ");
  1482.       if (aOffset > 0) {
  1483.         var cmd = aURL.substr(0, aOffset);
  1484.         var text = aURL.substr(aOffset+1);
  1485.         shortcutURL = BMSVC.resolveKeyword(cmd, aPostDataRef);
  1486.         if (shortcutURL && text) {
  1487.           if (aPostDataRef && aPostDataRef.value) {
  1488.             // XXXben - currently we only support "application/x-www-form-urlencoded"
  1489.             //          enctypes.
  1490.             aPostDataRef.value = unescape(aPostDataRef.value);
  1491.             if (aPostDataRef.value.match(/%s/))
  1492.               aPostDataRef.value = getPostDataStream(aPostDataRef.value, text, 
  1493.                                                      "application/x-www-form-urlencoded");
  1494.             else {
  1495.               shortcutURL = null;
  1496.               aPostDataRef.value = null;
  1497.             }
  1498.           }
  1499.           else
  1500.             shortcutURL = shortcutURL.match(/%s/) ? shortcutURL.replace(/%s/g, encodeURIComponent(text)) : null;
  1501.         }
  1502.       }
  1503.     }
  1504.  
  1505.     if (shortcutURL)
  1506.       aURL = shortcutURL;
  1507.  
  1508.   } catch (ex) {
  1509.   }
  1510.   return aURL;
  1511. }
  1512.  
  1513. function getPostDataStream(aStringData, aKeyword, aType)
  1514. {
  1515.   var dataStream = Components.classes["@mozilla.org/io/string-input-stream;1"]
  1516.                             .createInstance(Components.interfaces.nsIStringInputStream);
  1517.   aStringData = aStringData.replace(/%s/g, encodeURIComponent(aKeyword));
  1518.   dataStream.setData(aStringData, aStringData.length);
  1519.  
  1520.   var mimeStream = Components.classes["@mozilla.org/network/mime-input-stream;1"]
  1521.                               .createInstance(Components.interfaces.nsIMIMEInputStream);
  1522.   mimeStream.addHeader("Content-Type", aType);
  1523.   mimeStream.addContentLength = true;
  1524.   mimeStream.setData(dataStream);
  1525.   return mimeStream.QueryInterface(Components.interfaces.nsIInputStream);
  1526. }
  1527.  
  1528.  
  1529. function readFromClipboard()
  1530. {
  1531.   var url;
  1532.  
  1533.   try {
  1534.     // Get clipboard.
  1535.     var clipboard = Components.classes["@mozilla.org/widget/clipboard;1"]
  1536.                               .getService(Components.interfaces.nsIClipboard);
  1537.  
  1538.     // Create tranferable that will transfer the text.
  1539.     var trans = Components.classes["@mozilla.org/widget/transferable;1"]
  1540.                           .createInstance(Components.interfaces.nsITransferable);
  1541.  
  1542.     trans.addDataFlavor("text/unicode");
  1543.  
  1544.     // If available, use selection clipboard, otherwise global one
  1545.     if (clipboard.supportsSelectionClipboard())
  1546.       clipboard.getData(trans, clipboard.kSelectionClipboard);
  1547.     else
  1548.       clipboard.getData(trans, clipboard.kGlobalClipboard);
  1549.  
  1550.     var data = {};
  1551.     var dataLen = {};
  1552.     trans.getTransferData("text/unicode", data, dataLen);
  1553.  
  1554.     if (data) {
  1555.       data = data.value.QueryInterface(Components.interfaces.nsISupportsString);
  1556.       url = data.data.substring(0, dataLen.value / 2);
  1557.     }
  1558.   } catch (ex) {
  1559.   }
  1560.  
  1561.   return url;
  1562. }
  1563.  
  1564. function BrowserViewSourceOfDocument(aDocument)
  1565. {
  1566.   var docCharset;
  1567.   var pageCookie;
  1568.   var webNav;
  1569.  
  1570.   // Get the document charset
  1571.   docCharset = "charset=" + aDocument.characterSet;
  1572.  
  1573.   // Get the nsIWebNavigation associated with the document
  1574.   try {
  1575.       var win;
  1576.       var ifRequestor;
  1577.  
  1578.       // Get the DOMWindow for the requested document.  If the DOMWindow
  1579.       // cannot be found, then just use the _content window...
  1580.       //
  1581.       // XXX:  This is a bit of a hack...
  1582.       win = aDocument.defaultView;
  1583.       if (win == window) {
  1584.         win = _content;
  1585.       }
  1586.       ifRequestor = win.QueryInterface(Components.interfaces.nsIInterfaceRequestor);
  1587.  
  1588.       webNav = ifRequestor.getInterface(nsIWebNavigation);
  1589.   } catch(err) {
  1590.       // If nsIWebNavigation cannot be found, just get the one for the whole
  1591.       // window...
  1592.       webNav = getWebNavigation();
  1593.   }
  1594.   //
  1595.   // Get the 'PageDescriptor' for the current document. This allows the
  1596.   // view-source to access the cached copy of the content rather than
  1597.   // refetching it from the network...
  1598.   //
  1599.   try{
  1600.     var PageLoader = webNav.QueryInterface(Components.interfaces.nsIWebPageDescriptor);
  1601.  
  1602.     pageCookie = PageLoader.currentDescriptor;
  1603.   } catch(err) {
  1604.     // If no page descriptor is available, just use the view-source URL...
  1605.   }
  1606.  
  1607.   BrowserViewSourceOfURL(webNav.currentURI.spec, docCharset, pageCookie);
  1608. }
  1609.  
  1610. function BrowserViewSourceOfURL(url, charset, pageCookie)
  1611. {
  1612.   // try to open a view-source window while inheriting the charset (if any)
  1613.   openDialog("chrome://global/content/viewSource.xul",
  1614.              "_blank",
  1615.              "scrollbars,resizable,chrome,dialog=no",
  1616.              url, charset, pageCookie);
  1617. }
  1618.  
  1619. // doc=null for regular page info, doc=owner document for frame info.
  1620. function BrowserPageInfo(doc)
  1621. {
  1622.   window.openDialog("chrome://browser/content/pageInfo.xul",
  1623.                     "_blank",
  1624.                     "chrome,dialog=no",
  1625.                     doc);
  1626. }
  1627.  
  1628.  
  1629. function checkForDirectoryListing()
  1630. {
  1631.   if ( "HTTPIndex" in _content &&
  1632.        _content.HTTPIndex instanceof Components.interfaces.nsIHTTPIndex ) {
  1633.     _content.defaultCharacterset = getMarkupDocumentViewer().defaultCharacterSet;
  1634.   }
  1635. }
  1636.  
  1637. function URLBarFocusHandler(aEvent, aElt)
  1638. {
  1639.   if (gIgnoreFocus)
  1640.     gIgnoreFocus = false;
  1641.   else if (gClickSelectsAll)
  1642.     aElt.select();
  1643. }
  1644.  
  1645. function URLBarMouseDownHandler(aEvent, aElt)
  1646. {
  1647.   if (aElt.hasAttribute("focused")) {
  1648.     gIgnoreClick = true;
  1649.   } else {
  1650.     gIgnoreFocus = true;
  1651.     gIgnoreClick = false;
  1652.     aElt.setSelectionRange(0, 0);
  1653.   }
  1654. }
  1655.  
  1656. function URLBarClickHandler(aEvent, aElt)
  1657. {
  1658.   if (!gIgnoreClick && gClickSelectsAll && aElt.selectionStart == aElt.selectionEnd)
  1659.     aElt.select();
  1660. }
  1661.  
  1662. // If "ESC" is pressed in the url bar, we replace the urlbar's value with the url of the page
  1663. // and highlight it, unless it is about:blank, where we reset it to "".
  1664. function handleURLBarRevert()
  1665. {
  1666.   var url = getWebNavigation().currentURI.spec;
  1667.   var throbberElement = document.getElementById("navigator-throbber");
  1668.  
  1669.   var isScrolling = gURLBar.popupOpen;
  1670.   
  1671.   // don't revert to last valid url unless page is NOT loading
  1672.   // and user is NOT key-scrolling through autocomplete list
  1673.   if ((!throbberElement || !throbberElement.hasAttribute("busy")) && !isScrolling) {
  1674.     if (url != "about:blank") { 
  1675.       gURLBar.value = url;
  1676.       gURLBar.select();
  1677.       SetPageProxyState("valid", null); // XXX Build a URI and pass it in here.
  1678.     } else { //if about:blank, urlbar becomes ""
  1679.       gURLBar.value = "";
  1680.     }
  1681.   }
  1682.   
  1683.   gBrowser.userTypedValue = null;
  1684.  
  1685.   // tell widget to revert to last typed text only if the user
  1686.   // was scrolling when they hit escape
  1687.   return !isScrolling; 
  1688. }
  1689.  
  1690. function handleURLBarCommand(aTriggeringEvent)
  1691. {
  1692.   var postData = { };
  1693.   canonizeUrl(aTriggeringEvent, postData);
  1694.  
  1695.   try { 
  1696.     addToUrlbarHistory();
  1697.   } catch (ex) {
  1698.     // Things may go wrong when adding url to session history,
  1699.     // but don't let that interfere with the loading of the url.
  1700.   }
  1701.   
  1702.   BrowserLoadURL(aTriggeringEvent, postData.value); 
  1703. }
  1704.  
  1705. function canonizeUrl(aTriggeringEvent, aPostDataRef)
  1706. {
  1707.   if (!gURLBar)
  1708.     return;
  1709.   
  1710.   var url = gURLBar.value;
  1711.  
  1712.   // Prevent suffix when already exists www , http , /
  1713.   if (!/^(www|http)|\/\s*$/i.test(url)) {
  1714.     var suffix = null;
  1715.  
  1716.     if (aTriggeringEvent && 'ctrlKey' in aTriggeringEvent &&
  1717.         aTriggeringEvent.ctrlKey && 'shiftKey' in aTriggeringEvent &&
  1718.         aTriggeringEvent.shiftKey)
  1719.       suffix = ".org/";
  1720.  
  1721.     else if (aTriggeringEvent && 'ctrlKey' in aTriggeringEvent &&
  1722.         aTriggeringEvent.ctrlKey)
  1723.       suffix = ".com/";
  1724.  
  1725.     else if (aTriggeringEvent && 'shiftKey' in aTriggeringEvent &&
  1726.         aTriggeringEvent.shiftKey)
  1727.       suffix = ".net/";
  1728.  
  1729.     if (suffix != null) {
  1730.       // trim leading/trailing spaces (bug 233205)
  1731.       url = url.replace( /^\s+/, "");
  1732.       url = url.replace( /\s+$/, "");
  1733.       // Tack www. and suffix on.
  1734.       url = "http://www." + url + suffix;
  1735.     }
  1736.   }
  1737.  
  1738.   gURLBar.value = getShortcutOrURI(url, aPostDataRef);
  1739. }
  1740.  
  1741. function UpdatePageProxyState()
  1742. {
  1743.   if (gURLBar && gURLBar.value != gLastValidURLStr)
  1744.     SetPageProxyState("invalid", null);
  1745. }
  1746.  
  1747. function SetPageProxyState(aState, aURI)
  1748. {
  1749.   if (!gURLBar)
  1750.     return;
  1751.  
  1752.   if (!gProxyButton)
  1753.     gProxyButton = document.getElementById("page-proxy-button");
  1754.   if (!gProxyFavIcon)
  1755.     gProxyFavIcon = document.getElementById("page-proxy-favicon");
  1756.   if (!gProxyDeck)
  1757.     gProxyDeck = document.getElementById("page-proxy-deck");
  1758.  
  1759.   gProxyButton.setAttribute("pageproxystate", aState);
  1760.  
  1761.   // the page proxy state is set to valid via OnLocationChange, which
  1762.   // gets called when we switch tabs.  We'll let updatePageFavIcon
  1763.   // take care of updating the mFavIconURL because it knows exactly
  1764.   // for which tab to update things, instead of confusing the issue
  1765.   // here.
  1766.   if (aState == "valid") {
  1767.     gLastValidURLStr = gURLBar.value;
  1768.     gURLBar.addEventListener("input", UpdatePageProxyState, false);
  1769.  
  1770.     if (gBrowser.mCurrentBrowser.mFavIconURL != null) {
  1771.       if (gBrowser.isFavIconKnownMissing(gBrowser.mCurrentBrowser.mFavIconURL)) {
  1772.         gBrowser.mFavIconURL = null;
  1773.         PageProxyClearIcon();
  1774.       } else {
  1775.         PageProxySetIcon(gBrowser.mCurrentBrowser.mFavIconURL);
  1776.       }
  1777.     } else {
  1778.       PageProxyClearIcon();
  1779.     }
  1780.   } else if (aState == "invalid") {
  1781.     gURLBar.removeEventListener("input", UpdatePageProxyState, false);
  1782.     PageProxyClearIcon();
  1783.   }
  1784. }
  1785.  
  1786. function PageProxySetIcon (aURL)
  1787. {
  1788.   if (!gProxyFavIcon)
  1789.     return;
  1790.  
  1791.   if (gProxyFavIcon.getAttribute("src") != aURL)
  1792.     gProxyFavIcon.setAttribute("src", aURL);
  1793.   else if (gProxyDeck.selectedIndex != 1)
  1794.     gProxyDeck.selectedIndex = 1;
  1795. }
  1796.  
  1797. function PageProxyClearIcon ()
  1798. {
  1799.   if (gProxyDeck.selectedIndex != 0)
  1800.     gProxyDeck.selectedIndex = 0;
  1801.   if (gProxyFavIcon.hasAttribute("src"))
  1802.     gProxyFavIcon.removeAttribute("src");
  1803. }
  1804.  
  1805. function PageProxyDragGesture(aEvent)
  1806. {
  1807.   if (gProxyButton.getAttribute("pageproxystate") == "valid") {
  1808.     nsDragAndDrop.startDrag(aEvent, proxyIconDNDObserver);
  1809.     return true;
  1810.   }
  1811.   return false;
  1812. }
  1813.  
  1814. function URLBarOnDrop(evt)
  1815. {
  1816.   nsDragAndDrop.drop(evt, urlbarObserver);
  1817. }
  1818.  
  1819. var urlbarObserver = {
  1820.   onDrop: function (aEvent, aXferData, aDragSession)
  1821.     {
  1822.       var url = transferUtils.retrieveURLFromData(aXferData.data, aXferData.flavour.contentType);
  1823.  
  1824.       // The URL bar automatically handles inputs with newline characters, 
  1825.       // so we can get away with treating text/x-moz-url flavours as text/unicode.
  1826.       if (url) {
  1827.         getBrowser().dragDropSecurityCheck(aEvent, aDragSession, url);
  1828.  
  1829.         // XXXBlake Workaround caret crash when you try to set the textbox's value on dropping
  1830.         setTimeout(function(u) { gURLBar.value = u; handleURLBarCommand(); }, 0, url);
  1831.       }
  1832.     },
  1833.   getSupportedFlavours: function ()
  1834.     {
  1835.       var flavourSet = new FlavourSet();
  1836.  
  1837.       // Plain text drops are often misidentified as "text/x-moz-url", so favor plain text.
  1838.       flavourSet.appendFlavour("text/unicode");
  1839.       flavourSet.appendFlavour("text/x-moz-url");
  1840.       flavourSet.appendFlavour("application/x-moz-file", "nsIFile");     
  1841.       return flavourSet;
  1842.     }
  1843. }
  1844.  
  1845. function updateToolbarStates(toolbarMenuElt)
  1846. {
  1847.   if (!gHaveUpdatedToolbarState) {
  1848.     var mainWindow = document.getElementById("main-window");
  1849.     if (mainWindow.hasAttribute("chromehidden")) {
  1850.       gHaveUpdatedToolbarState = true;
  1851.       var i;
  1852.       for (i = 0; i < toolbarMenuElt.childNodes.length; ++i)
  1853.         document.getElementById(toolbarMenuElt.childNodes[i].getAttribute("observes")).removeAttribute("checked");
  1854.       var toolbars = document.getElementsByTagName("toolbar");
  1855.       
  1856.       // Start i at 1, since we skip the menubar.
  1857.       for (i = 1; i < toolbars.length; ++i) {
  1858.         if (toolbars[i].getAttribute("class").indexOf("chromeclass") != -1)
  1859.           toolbars[i].setAttribute("collapsed", "true");
  1860.       }
  1861.       var statusbars = document.getElementsByTagName("statusbar");
  1862.       for (i = 1; i < statusbars.length; ++i) {
  1863.         if (statusbars[i].getAttribute("class").indexOf("chromeclass") != -1)
  1864.           statusbars[i].setAttribute("collapsed", "true");
  1865.       }
  1866.       mainWindow.removeAttribute("chromehidden");
  1867.     }
  1868.   }
  1869. }
  1870.  
  1871. function BrowserImport()
  1872. {
  1873.   var features = "modal,centerscreen,chrome,resizable=no";
  1874.   window.openDialog("chrome://browser/content/migration/migration.xul", "migration", features);
  1875. }
  1876.  
  1877. function BrowserFullScreen()
  1878. {
  1879.   window.fullScreen = !window.fullScreen;
  1880. }
  1881.  
  1882. function onFullScreen()
  1883. {
  1884.   FullScreen.toggle();
  1885. }
  1886.  
  1887. function getWebNavigation()
  1888. {
  1889.   try {
  1890.     return gBrowser.webNavigation;
  1891.   } catch (e) {
  1892.     return null;
  1893.   }
  1894. }
  1895.  
  1896. function BrowserReloadWithFlags(reloadFlags)
  1897. {
  1898.   /* First, we'll try to use the session history object to reload so 
  1899.    * that framesets are handled properly. If we're in a special 
  1900.    * window (such as view-source) that has no session history, fall 
  1901.    * back on using the web navigation's reload method.
  1902.    */
  1903.  
  1904.   var webNav = getWebNavigation();
  1905.   try {
  1906.     var sh = webNav.sessionHistory;
  1907.     if (sh)
  1908.       webNav = sh.QueryInterface(nsIWebNavigation);
  1909.   } catch (e) {
  1910.   }
  1911.  
  1912.   try {
  1913.     webNav.reload(reloadFlags);
  1914.   } catch (e) {
  1915.   }
  1916. }
  1917.  
  1918. function toggleAffectedChrome(aHide)
  1919. {
  1920.   // chrome to toggle includes:
  1921.   //   (*) menubar
  1922.   //   (*) navigation bar
  1923.   //   (*) bookmarks toolbar
  1924.   //   (*) sidebar
  1925.   //   (*) find bar
  1926.   //   (*) statusbar
  1927.  
  1928.   var navToolbox = document.getElementById("navigator-toolbox");
  1929.   navToolbox.hidden = aHide;
  1930.   var statusbar = document.getElementById("status-bar");
  1931.   statusbar.hidden = aHide;
  1932.   if (aHide)
  1933.   {
  1934.     gChromeState = {};
  1935.     var sidebar = document.getElementById("sidebar-box");
  1936.     gChromeState.sidebarOpen = !sidebar.hidden;
  1937.     gSidebarCommand = sidebar.getAttribute("sidebarcommand");
  1938.       
  1939.     var findBar = document.getElementById("FindToolbar");
  1940.     gChromeState.findOpen = !findBar.hidden;
  1941.     closeFindBar();
  1942.   }
  1943.   else {
  1944.     if (gChromeState.findOpen)
  1945.       openFindBar();
  1946.   }
  1947.   
  1948.   if (gChromeState.sidebarOpen)
  1949.     toggleSidebar(gSidebarCommand);
  1950. }
  1951.  
  1952. function onEnterPrintPreview()
  1953. {
  1954.   toggleAffectedChrome(true);
  1955. }
  1956.  
  1957. function onExitPrintPreview()
  1958. {
  1959.   // restore chrome to original state
  1960.   toggleAffectedChrome(false);
  1961. }
  1962.  
  1963. function getMarkupDocumentViewer()
  1964. {
  1965.   return gBrowser.markupDocumentViewer;
  1966. }
  1967.  
  1968. /**
  1969.  * Content area tooltip.
  1970.  * XXX - this must move into XBL binding/equiv! Do not want to pollute
  1971.  *       browser.js with functionality that can be encapsulated into
  1972.  *       browser widget. TEMPORARY!
  1973.  *
  1974.  * NOTE: Any changes to this routine need to be mirrored in ChromeListener::FindTitleText()
  1975.  *       (located in mozilla/embedding/browser/webBrowser/nsDocShellTreeOwner.cpp)
  1976.  *       which performs the same function, but for embedded clients that
  1977.  *       don't use a XUL/JS layer. It is important that the logic of
  1978.  *       these two routines be kept more or less in sync.
  1979.  *       (pinkerton)
  1980.  **/
  1981. function FillInHTMLTooltip(tipElement)
  1982. {
  1983.   var retVal = false;
  1984.   if (tipElement.namespaceURI == "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul")
  1985.     return retVal;
  1986.  
  1987.   const XLinkNS = "http://www.w3.org/1999/xlink";
  1988.  
  1989.  
  1990.   var titleText = null;
  1991.   var XLinkTitleText = null;
  1992.   
  1993.   while (!titleText && !XLinkTitleText && tipElement) {
  1994.     if (tipElement.nodeType == Node.ELEMENT_NODE) {
  1995.       titleText = tipElement.getAttribute("title");
  1996.       XLinkTitleText = tipElement.getAttributeNS(XLinkNS, "title");
  1997.     }
  1998.     tipElement = tipElement.parentNode;
  1999.   }
  2000.  
  2001.   var texts = [titleText, XLinkTitleText];
  2002.   var tipNode = document.getElementById("aHTMLTooltip");
  2003.  
  2004.   for (var i = 0; i < texts.length; ++i) {
  2005.     var t = texts[i];
  2006.     if (t && t.search(/\S/) >= 0) {
  2007.       tipNode.setAttribute("label", t);
  2008.       retVal = true;
  2009.     }
  2010.   }
  2011.  
  2012.   return retVal;
  2013. }
  2014.  
  2015. var proxyIconDNDObserver = {
  2016.   onDragStart: function (aEvent, aXferData, aDragAction)
  2017.     {
  2018.       var value = gURLBar.value;
  2019.       // XXX - do we want to allow the user to set a blank page to their homepage?
  2020.       //       if so then we want to modify this a little to set about:blank as
  2021.       //       the homepage in the event of an empty urlbar.
  2022.       if (!value) return;
  2023.  
  2024.       var urlString = value + "\n" + window._content.document.title;
  2025.       var htmlString = "<a href=\"" + value + "\">" + value + "</a>";
  2026.  
  2027.       aXferData.data = new TransferData();
  2028.       aXferData.data.addDataForFlavour("text/x-moz-url", urlString);
  2029.       aXferData.data.addDataForFlavour("text/unicode", value);
  2030.       aXferData.data.addDataForFlavour("text/html", htmlString);
  2031.  
  2032.       // we're copying the URL from the proxy icon, not moving
  2033.       // we specify all of them though, because d&d sucks and OS's
  2034.       // get confused if they don't get the one they want
  2035.       aDragAction.action =
  2036.         Components.interfaces.nsIDragService.DRAGDROP_ACTION_COPY |
  2037.         Components.interfaces.nsIDragService.DRAGDROP_ACTION_MOVE |
  2038.         Components.interfaces.nsIDragService.DRAGDROP_ACTION_LINK;
  2039.     }
  2040. }
  2041.  
  2042. var homeButtonObserver = {
  2043.   onDrop: function (aEvent, aXferData, aDragSession)
  2044.     {
  2045.       var url = transferUtils.retrieveURLFromData(aXferData.data, aXferData.flavour.contentType);
  2046.       setTimeout(openHomeDialog, 0, url);
  2047.     },
  2048.  
  2049.   onDragOver: function (aEvent, aFlavour, aDragSession)
  2050.     {
  2051.       var statusTextFld = document.getElementById("statusbar-display");
  2052.       statusTextFld.label = gNavigatorBundle.getString("droponhomebutton");
  2053.       aDragSession.dragAction = Components.interfaces.nsIDragService.DRAGDROP_ACTION_LINK;
  2054.     },
  2055.  
  2056.   onDragExit: function (aEvent, aDragSession)
  2057.     {
  2058.       var statusTextFld = document.getElementById("statusbar-display");
  2059.       statusTextFld.label = "";
  2060.     },
  2061.  
  2062.   getSupportedFlavours: function ()
  2063.     {
  2064.       var flavourSet = new FlavourSet();
  2065.       flavourSet.appendFlavour("application/x-moz-file", "nsIFile");
  2066.       flavourSet.appendFlavour("text/x-moz-url");
  2067.       flavourSet.appendFlavour("text/unicode");
  2068.       return flavourSet;
  2069.     }
  2070. }
  2071.  
  2072. function openHomeDialog(aURL)
  2073. {
  2074.   var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService(Components.interfaces.nsIPromptService);
  2075.   var promptTitle = gNavigatorBundle.getString("droponhometitle");
  2076.   var promptMsg   = gNavigatorBundle.getString("droponhomemsg");
  2077.   var pressedVal  = promptService.confirmEx(window, promptTitle, promptMsg,
  2078.                           (promptService.BUTTON_TITLE_YES * promptService.BUTTON_POS_0) +
  2079.                           (promptService.BUTTON_TITLE_NO * promptService.BUTTON_POS_1),
  2080.                           null, null, null, null, {value:0});
  2081.  
  2082.   if (pressedVal == 0) {
  2083.     try {
  2084.       var str = Components.classes["@mozilla.org/supports-string;1"]
  2085.                           .createInstance(Components.interfaces.nsISupportsString);
  2086.       str.data = aURL;
  2087.       gPrefService.setComplexValue("browser.startup.homepage",
  2088.                                    Components.interfaces.nsISupportsString, str);
  2089.       var homeButton = document.getElementById("home-button");
  2090.       homeButton.setAttribute("tooltiptext", aURL);
  2091.     } catch (ex) {
  2092.       dump("Failed to set the home page.\n"+ex+"\n");
  2093.     }
  2094.   }
  2095. }
  2096.  
  2097. var bookmarksButtonObserver = {
  2098.   onDrop: function (aEvent, aXferData, aDragSession)
  2099.   {
  2100.     var split = aXferData.data.split("\n");
  2101.     var url = split[0];
  2102.     if (url != aXferData.data) {  //do nothing if it's not a valid URL
  2103.       var name = split[1];
  2104.       openDialog("chrome://browser/content/bookmarks/addBookmark2.xul", "",
  2105.                  "centerscreen,chrome,dialog,resizable,dependent", name, url);
  2106.     }
  2107.   },
  2108.  
  2109.   onDragOver: function (aEvent, aFlavour, aDragSession)
  2110.   {
  2111.     var statusTextFld = document.getElementById("statusbar-display");
  2112.     statusTextFld.label = gNavigatorBundle.getString("droponbookmarksbutton");
  2113.     aDragSession.dragAction = Components.interfaces.nsIDragService.DRAGDROP_ACTION_LINK;
  2114.   },
  2115.  
  2116.   onDragExit: function (aEvent, aDragSession)
  2117.   {
  2118.     var statusTextFld = document.getElementById("statusbar-display");
  2119.     statusTextFld.label = "";
  2120.   },
  2121.  
  2122.   getSupportedFlavours: function ()
  2123.   {
  2124.     var flavourSet = new FlavourSet();
  2125.     flavourSet.appendFlavour("application/x-moz-file", "nsIFile");
  2126.     flavourSet.appendFlavour("text/x-moz-url");
  2127.     flavourSet.appendFlavour("text/unicode");
  2128.     return flavourSet;
  2129.   }
  2130. }
  2131.  
  2132. var goButtonObserver = {
  2133.   onDragOver: function(aEvent, aFlavour, aDragSession)
  2134.     {
  2135.       var statusTextFld = document.getElementById("statusbar-display");
  2136.       statusTextFld.label = gNavigatorBundle.getString("dropongobutton");
  2137.       aEvent.target.setAttribute("dragover", "true");
  2138.       return true;
  2139.     },
  2140.   onDragExit: function (aEvent, aDragSession)
  2141.     {
  2142.       var statusTextFld = document.getElementById("statusbar-display");
  2143.       statusTextFld.label = "";
  2144.       aEvent.target.removeAttribute("dragover");
  2145.     },
  2146.   onDrop: function (aEvent, aXferData, aDragSession)
  2147.     {
  2148.       var xferData = aXferData.data.split("\n");
  2149.       var uri = xferData[0] ? xferData[0] : xferData[1];
  2150.       if (uri) {
  2151.         getBrowser().dragDropSecurityCheck(aEvent, aDragSession, uri);
  2152.  
  2153.         loadURI(uri, null, null);
  2154.       }
  2155.     },
  2156.   getSupportedFlavours: function ()
  2157.     {
  2158.       var flavourSet = new FlavourSet();
  2159.       flavourSet.appendFlavour("application/x-moz-file", "nsIFile");
  2160.       flavourSet.appendFlavour("text/x-moz-url");
  2161.       flavourSet.appendFlavour("text/unicode");
  2162.       return flavourSet;
  2163.     }
  2164. }
  2165.  
  2166. var DownloadsButtonDNDObserver = {
  2167.   /////////////////////////////////////////////////////////////////////////////
  2168.   // nsDragAndDrop
  2169.   onDragOver: function (aEvent, aFlavour, aDragSession)
  2170.   {
  2171.     var statusTextFld = document.getElementById("statusbar-display");
  2172.     statusTextFld.label = gNavigatorBundle.getString("dropondownloadsbutton");
  2173.     aDragSession.canDrop = (aFlavour.contentType == "text/x-moz-url" || 
  2174.                             aFlavour.contentType == "text/unicode");
  2175.   },
  2176.  
  2177.   onDragExit: function (aEvent, aDragSession)
  2178.   {
  2179.     var statusTextFld = document.getElementById("statusbar-display");
  2180.     statusTextFld.label = "";
  2181.   },
  2182.  
  2183.   onDrop: function (aEvent, aXferData, aDragSession)
  2184.   {
  2185.     var split = aXferData.data.split("\n");
  2186.     var url = split[0];
  2187.     if (url != aXferData.data) {  //do nothing, not a valid URL
  2188.       getBrowser().dragDropSecurityCheck(aEvent, aDragSession, url);
  2189.  
  2190.       var name = split[1];
  2191.       saveURL(url, name, null, true, true);
  2192.     }
  2193.   },
  2194.   getSupportedFlavours: function ()
  2195.   {
  2196.     var flavourSet = new FlavourSet();
  2197.     flavourSet.appendFlavour("text/x-moz-url");
  2198.     flavourSet.appendFlavour("text/unicode");
  2199.     return flavourSet;
  2200.   }
  2201. }
  2202.  
  2203. function focusSearchBar()
  2204. {
  2205.   var searchBar = document.getElementsByTagName("searchbar");
  2206.   if (searchBar.length > 0) {
  2207.     searchBar[0].select();
  2208.     searchBar[0].focus();
  2209.   }
  2210. }
  2211.  
  2212. function OpenSearch(tabName, searchStr, newTabFlag)
  2213. {
  2214.   //This function needs to be split up someday.
  2215.   //XXXnoririty I don't want any prefs switching open by tabs to window
  2216.   //XXXpch: this routine needs to be cleaned up.
  2217.  
  2218.   var defaultSearchURL = null;
  2219.   var navigatorRegionBundle = document.getElementById("bundle_browser_region");
  2220.   var fallbackDefaultSearchURL = navigatorRegionBundle.getString("fallbackDefaultSearchURL");
  2221.  
  2222.   //Check to see if search string contains "://" or "ftp." or white space.
  2223.   //If it does treat as url and match for pattern
  2224.   
  2225.   var urlmatch= /(:\/\/|^ftp\.)[^ \S]+$/ 
  2226.   var forceAsURL = urlmatch.test(searchStr);
  2227.  
  2228.   try {
  2229.     defaultSearchURL = gPrefService.getComplexValue("browser.search.defaulturl",
  2230.                                             Components.interfaces.nsIPrefLocalizedString).data;
  2231.   } catch (ex) {
  2232.   }
  2233.  
  2234.   // Fallback to a default url (one that we can get sidebar search results for)
  2235.   if (!defaultSearchURL)
  2236.     defaultSearchURL = fallbackDefaultSearchURL;
  2237.  
  2238.   if (!searchStr) {
  2239.     BrowserSearchInternet();
  2240.   } else {
  2241.  
  2242.     //Check to see if location bar field is a url
  2243.     //If it is a url go to URL.  A Url is "://" or "." as commented above
  2244.     //Otherwise search on entry
  2245.     if (forceAsURL) {
  2246.        BrowserLoadURL(null, null)
  2247.     } else {
  2248.       if (searchStr) {
  2249.         var escapedSearchStr = encodeURIComponent(searchStr);
  2250.         defaultSearchURL += escapedSearchStr;
  2251.         var searchDS = Components.classes["@mozilla.org/rdf/datasource;1?name=internetsearch"]
  2252.                                  .getService(Components.interfaces.nsIInternetSearchService);
  2253.  
  2254.         searchDS.RememberLastSearchText(escapedSearchStr);
  2255.         try {
  2256.           var searchEngineURI = gPrefService.getCharPref("browser.search.defaultengine");
  2257.           if (searchEngineURI) {          
  2258.             var searchURL = getSearchUrl("actionButton");
  2259.             if (searchURL) {
  2260.               defaultSearchURL = searchURL + escapedSearchStr; 
  2261.             } else {
  2262.               searchURL = searchDS.GetInternetSearchURL(searchEngineURI, escapedSearchStr, 0, 0, {value:0});
  2263.               if (searchURL)
  2264.                 defaultSearchURL = searchURL;
  2265.             }
  2266.           }
  2267.         } catch (ex) {
  2268.         }
  2269.  
  2270.         if (!newTabFlag) {
  2271.           loadURI(defaultSearchURL, null, null);
  2272.         }
  2273.         else {
  2274.           var newTab = getBrowser().addTab(defaultSearchURL);
  2275.           if (!pref.getBoolPref("browser.tabs.loadInBackground"))
  2276.             getBrowser().selectedTab = newTab;
  2277.         }
  2278.       }
  2279.     }
  2280.   }
  2281. }
  2282.  
  2283. function FillHistoryMenu(aParent, aMenu)
  2284.   {
  2285.     // Remove old entries if any
  2286.     deleteHistoryItems(aParent);
  2287.  
  2288.     var sessionHistory = getWebNavigation().sessionHistory;
  2289.  
  2290.     var count = sessionHistory.count;
  2291.     var index = sessionHistory.index;
  2292.     var end;
  2293.     var j;
  2294.     var entry;
  2295.  
  2296.     switch (aMenu)
  2297.       {
  2298.         case "back":
  2299.           end = (index > MAX_HISTORY_MENU_ITEMS) ? index - MAX_HISTORY_MENU_ITEMS : 0;
  2300.           if ((index - 1) < end) return false;
  2301.           for (j = index - 1; j >= end; j--)
  2302.             {
  2303.               entry = sessionHistory.getEntryAtIndex(j, false);
  2304.               if (entry)
  2305.                 createMenuItem(aParent, j, entry.title);
  2306.             }
  2307.           break;
  2308.         case "forward":
  2309.           end  = ((count-index) > MAX_HISTORY_MENU_ITEMS) ? index + MAX_HISTORY_MENU_ITEMS : count;
  2310.           if ((index + 1) >= end) return false;
  2311.           for (j = index + 1; j < end; j++)
  2312.             {
  2313.               entry = sessionHistory.getEntryAtIndex(j, false);
  2314.               if (entry)
  2315.                 createMenuItem(aParent, j, entry.title);
  2316.             }
  2317.           break;
  2318.         case "go":
  2319.           aParent.lastChild.hidden = (count == 0);
  2320.           end = count > MAX_HISTORY_MENU_ITEMS ? count - MAX_HISTORY_MENU_ITEMS : 0;
  2321.           for (j = count - 1; j >= end; j--)
  2322.             {
  2323.               entry = sessionHistory.getEntryAtIndex(j, false);
  2324.               if (entry)
  2325.                 createRadioMenuItem(aParent, j, entry.title, j==index);
  2326.             }
  2327.           break;
  2328.       }
  2329.     return true;
  2330.   }
  2331.  
  2332. function addToUrlbarHistory()
  2333. {
  2334.   var urlToAdd = gURLBar.value;
  2335.   if (!urlToAdd)
  2336.      return;
  2337.   if (urlToAdd.search(/[\x00-\x1F]/) != -1) // don't store bad URLs
  2338.      return;
  2339.  
  2340.   if (!gGlobalHistory)
  2341.     gGlobalHistory = Components.classes["@mozilla.org/browser/global-history;2"]
  2342.                                .getService(Components.interfaces.nsIBrowserHistory);
  2343.   
  2344.   if (!gURIFixup)
  2345.     gURIFixup = Components.classes["@mozilla.org/docshell/urifixup;1"]
  2346.                           .getService(Components.interfaces.nsIURIFixup);
  2347.    try {
  2348.      if (urlToAdd.indexOf(" ") == -1) {
  2349.        var fixedUpURI = gURIFixup.createFixupURI(urlToAdd, 0);
  2350.        gGlobalHistory.markPageAsTyped(fixedUpURI);
  2351.      }
  2352.    }
  2353.    catch(ex) {
  2354.    }
  2355. }
  2356.  
  2357. function createMenuItem( aParent, aIndex, aLabel)
  2358.   {
  2359.     var menuitem = document.createElement( "menuitem" );
  2360.     menuitem.setAttribute( "label", aLabel );
  2361.     menuitem.setAttribute( "index", aIndex );
  2362.     aParent.appendChild( menuitem );
  2363.   }
  2364.  
  2365. function createRadioMenuItem( aParent, aIndex, aLabel, aChecked)
  2366.   {
  2367.     var menuitem = document.createElement( "menuitem" );
  2368.     menuitem.setAttribute( "type", "radio" );
  2369.     menuitem.setAttribute( "label", aLabel );
  2370.     menuitem.setAttribute( "index", aIndex );
  2371.     if (aChecked==true)
  2372.       menuitem.setAttribute( "checked", "true" );
  2373.     aParent.appendChild( menuitem );
  2374.   }
  2375.  
  2376. function deleteHistoryItems(aParent)
  2377. {
  2378.   var children = aParent.childNodes;
  2379.   for (var i = 0; i < children.length; i++)
  2380.     {
  2381.       var index = children[i].getAttribute("index");
  2382.       if (index)
  2383.         aParent.removeChild(children[i]);
  2384.     }
  2385. }
  2386.  
  2387. function toJavaScriptConsole()
  2388. {
  2389.   toOpenWindowByType("global:console", "chrome://global/content/console.xul");
  2390. }
  2391.  
  2392. function toOpenWindowByType(inType, uri, features)
  2393. {
  2394.   var windowManager = Components.classes['@mozilla.org/appshell/window-mediator;1'].getService();
  2395.   var windowManagerInterface = windowManager.QueryInterface(Components.interfaces.nsIWindowMediator);
  2396.   var topWindow = windowManagerInterface.getMostRecentWindow(inType);
  2397.   
  2398.   if (topWindow)
  2399.     topWindow.focus();
  2400.   else if (features)
  2401.     window.open(uri, "_blank", features);
  2402.   else
  2403.     window.open(uri, "_blank", "chrome,extrachrome,menubar,resizable,scrollbars,status,toolbar");
  2404. }
  2405.  
  2406.  
  2407. function OpenBrowserWindow()
  2408. {
  2409.   var charsetArg = new String();
  2410.   var handler = Components.classes['@mozilla.org/commandlinehandler/general-startup;1?type=browser'];
  2411.   handler = handler.getService();
  2412.   handler = handler.QueryInterface(Components.interfaces.nsICmdLineHandler);
  2413.   var startpage = handler.defaultArgs;
  2414.   var url = handler.chromeUrlForTask;
  2415.   var wintype = document.firstChild.getAttribute('windowtype');
  2416.  
  2417.   // if and only if the current window is a browser window and it has a document with a character
  2418.   // set, then extract the current charset menu setting from the current document and use it to
  2419.   // initialize the new browser window...
  2420.   if (window && (wintype == "navigator:browser") && window._content && window._content.document)
  2421.   {
  2422.     var DocCharset = window._content.document.characterSet;
  2423.     charsetArg = "charset="+DocCharset;
  2424.  
  2425.     //we should "inherit" the charset menu setting in a new window
  2426.     window.openDialog(url, "_blank", "chrome,all,dialog=no", startpage, charsetArg);
  2427.   }
  2428.   else // forget about the charset information.
  2429.   {
  2430.     window.openDialog(url, "_blank", "chrome,all,dialog=no", startpage);
  2431.   }
  2432. }
  2433.  
  2434. function openAboutDialog()
  2435. {
  2436.   window.openDialog("chrome://browser/content/aboutDialog.xul", "About", "modal,centerscreen,chrome,resizable=no");
  2437. }
  2438.  
  2439. function BrowserCustomizeToolbar()
  2440. {
  2441.   // Disable the toolbar context menu items
  2442.   var menubar = document.getElementById("main-menubar");
  2443.   for (var i = 0; i < menubar.childNodes.length; ++i)
  2444.     menubar.childNodes[i].setAttribute("disabled", true);
  2445.     
  2446.   var cmd = document.getElementById("cmd_CustomizeToolbars");
  2447.   cmd.setAttribute("disabled", "true");
  2448.   
  2449.   window.openDialog("chrome://global/content/customizeToolbar.xul", "CustomizeToolbar",
  2450.                     "chrome,all,dependent", document.getElementById("navigator-toolbox"));
  2451. }
  2452.  
  2453. function BrowserToolboxCustomizeDone(aToolboxChanged)
  2454. {
  2455.   // Update global UI elements that may have been added or removed
  2456.   if (aToolboxChanged) {
  2457.     gURLBar = document.getElementById("urlbar");
  2458.     gProxyButton = document.getElementById("page-proxy-button");
  2459.     gProxyFavIcon = document.getElementById("page-proxy-favicon");
  2460.     gProxyDeck = document.getElementById("page-proxy-deck");
  2461.     gHomeButton.updateTooltip();
  2462.     window.XULBrowserWindow.init();
  2463.   }
  2464.  
  2465.   // Update the urlbar
  2466.   var url = getWebNavigation().currentURI.spec;
  2467.   if (gURLBar) {
  2468.     gURLBar.value = url;
  2469.     var uri = Components.classes["@mozilla.org/network/standard-url;1"]
  2470.                         .createInstance(Components.interfaces.nsIURI);
  2471.     uri.spec = url;
  2472.     SetPageProxyState("valid", uri);
  2473.   }
  2474.  
  2475.   // Re-enable parts of the UI we disabled during the dialog
  2476.   var menubar = document.getElementById("main-menubar");
  2477.   for (var i = 0; i < menubar.childNodes.length; ++i)
  2478.     menubar.childNodes[i].setAttribute("disabled", false);
  2479.   var cmd = document.getElementById("cmd_CustomizeToolbars");
  2480.   cmd.removeAttribute("disabled");
  2481.  
  2482.   // fix up the personal toolbar folder
  2483.   var bt = document.getElementById("bookmarks-ptf");
  2484.   if (bt) {
  2485.     var btf = BMSVC.getBookmarksToolbarFolder().Value;
  2486.     var btchevron = document.getElementById("bookmarks-chevron");
  2487.     bt.ref = btf;
  2488.     btchevron.ref = btf;
  2489.     // no uniqueness is guaranteed, so we have to remove first
  2490.     try {
  2491.       bt.database.RemoveObserver(BookmarksToolbarRDFObserver);
  2492.       bt.controllers.removeController(BookmarksMenuController);
  2493.     } catch (ex) {
  2494.       // ignore
  2495.     }
  2496.     bt.database.AddObserver(BookmarksToolbarRDFObserver);
  2497.     bt.controllers.appendController(BookmarksMenuController);
  2498.     bt.builder.rebuild();
  2499.     btchevron.builder.rebuild();
  2500.  
  2501.     // fake a resize; this function takes care of flowing bookmarks
  2502.     // from the bar to the overflow item
  2503.     BookmarksToolbar.resizeFunc(null);
  2504.   }
  2505.  
  2506.   // XXX Shouldn't have to do this, but I do
  2507.   window.focus();
  2508. }
  2509.  
  2510. var FullScreen = 
  2511. {
  2512.   toggle: function()
  2513.   {
  2514.     // show/hide all menubars, toolbars, and statusbars (except the full screen toolbar)
  2515.     this.showXULChrome("toolbar", window.fullScreen);
  2516.     this.showXULChrome("statusbar", window.fullScreen);
  2517.   },
  2518.   
  2519.   showXULChrome: function(aTag, aShow)
  2520.   {
  2521.     var XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
  2522.     var els = document.getElementsByTagNameNS(XULNS, aTag);
  2523.     
  2524.     var i;
  2525.     for (i = 0; i < els.length; ++i) {
  2526.       // XXX don't interfere with previously collapsed toolbars
  2527.       if (els[i].getAttribute("fullscreentoolbar") == "true") {
  2528.         if (!aShow) {
  2529.           var toolbarMode = els[i].getAttribute("mode");
  2530.           var iconSize = els[i].getAttribute("iconsize");
  2531.           var contextMenu = els[i].getAttribute("context");
  2532.  
  2533.           if (toolbarMode != "text") {
  2534.             els[i].setAttribute("saved-mode", toolbarMode);
  2535.             els[i].setAttribute("saved-iconsize", iconSize);
  2536.             els[i].setAttribute("mode", "icons");
  2537.             els[i].setAttribute("iconsize", "small");
  2538.           }
  2539.  
  2540.           // XXX See bug 202978: we disable the context menu
  2541.           // to prevent customization while in fullscreen, which
  2542.           // causes menu breakage.
  2543.           els[i].setAttribute("saved-context", contextMenu);
  2544.           els[i].removeAttribute("context");
  2545.         }
  2546.         else {
  2547.           if (els[i].hasAttribute("saved-mode")) {
  2548.             var savedMode = els[i].getAttribute("saved-mode");
  2549.             els[i].setAttribute("mode", savedMode);
  2550.             els[i].removeAttribute("saved-mode");
  2551.           }
  2552.  
  2553.           if (els[i].hasAttribute("saved-iconsize")) {
  2554.             var savedIconSize = els[i].getAttribute("saved-iconsize");
  2555.             els[i].setAttribute("iconsize", savedIconSize);
  2556.             els[i].removeAttribute("saved-iconsize");
  2557.           }
  2558.  
  2559.           // XXX see above.
  2560.           if (els[i].hasAttribute("saved-context")) {
  2561.             var savedContext = els[i].getAttribute("saved-context");
  2562.             els[i].setAttribute("context", savedContext);
  2563.             els[i].removeAttribute("saved-context");
  2564.           }
  2565.         }
  2566.       } else {
  2567.         // use moz-collapsed so it doesn't persist hidden/collapsed,
  2568.         // so that new windows don't have missing toolbars
  2569.         if (aShow)
  2570.           els[i].removeAttribute("moz-collapsed");
  2571.         else
  2572.           els[i].setAttribute("moz-collapsed", "true");
  2573.       }
  2574.     }
  2575.     var controls = document.getElementsByAttribute("fullscreencontrol", "true");
  2576.     for (i = 0; i < controls.length; ++i)
  2577.       controls[i].hidden = aShow;
  2578.  
  2579.     // XXXvladimir this was a fix for bug 174174, but I don't think it's necessary
  2580.     // any more?
  2581.     var toolbox = document.getElementById("navigator-toolbox");
  2582.     if (!aShow) {
  2583.       var toolboxMode = toolbox.getAttribute("mode");
  2584.       var toolboxIconSize = toolbox.getAttribute("iconsize");
  2585.       if (toolboxMode != "text") {
  2586.         toolbox.setAttribute("saved-mode", toolboxMode);
  2587.         toolbox.setAttribute("saved-iconsize", toolboxIconSize);
  2588.         toolbox.setAttribute("mode", "icons");
  2589.         toolbox.setAttribute("iconsize", "small");
  2590.       }
  2591.       else {
  2592.         if (toolbox.hasAttribute("saved-mode")) {
  2593.           var savedMode = toolbox.getAttribute("saved-mode");
  2594.           toolbox.setAttribute("mode", savedMode);
  2595.           toolbox.removeAttribute("saved-mode");
  2596.         }
  2597.  
  2598.         if (toolbox.hasAttribute("saved-iconsize")) {
  2599.           var savedIconSize = toolbox.getAttribute("saved-iconsize");
  2600.           toolbox.setAttribute("iconsize", savedIconSize);
  2601.           toolbox.removeAttribute("saved-iconsize");
  2602.         }
  2603.       }
  2604.     }
  2605.   }
  2606. };
  2607.  
  2608. function nsBrowserStatusHandler()
  2609. {
  2610.   this.init();
  2611. }
  2612.  
  2613. nsBrowserStatusHandler.prototype =
  2614. {
  2615.   // Stored Status, Link and Loading values
  2616.   status : "",
  2617.   defaultStatus : "",
  2618.   jsStatus : "",
  2619.   jsDefaultStatus : "",
  2620.   overLink : "",
  2621.   startTime : 0,
  2622.   statusText: "",
  2623.   lastURI: null,
  2624.  
  2625.   statusTimeoutInEffect : false,
  2626.  
  2627.   QueryInterface : function(aIID)
  2628.   {
  2629.     if (aIID.equals(Components.interfaces.nsIWebProgressListener) ||
  2630.         aIID.equals(Components.interfaces.nsISupportsWeakReference) ||
  2631.         aIID.equals(Components.interfaces.nsIXULBrowserWindow) ||
  2632.         aIID.equals(Components.interfaces.nsISupports))
  2633.       return this;
  2634.     throw Components.results.NS_NOINTERFACE;
  2635.   },
  2636.  
  2637.   init : function()
  2638.   {
  2639.     this.throbberElement = document.getElementById("navigator-throbber");
  2640.     this.statusMeter     = document.getElementById("statusbar-icon");
  2641.     this.stopCommand     = document.getElementById("Browser:Stop");
  2642.     this.statusTextField = document.getElementById("statusbar-display");
  2643.     this.securityButton  = document.getElementById("security-button");
  2644.     this.urlBar          = document.getElementById("urlbar");
  2645.  
  2646.     // Initialize the security button's state and tooltip text
  2647.     const nsIWebProgressListener = Components.interfaces.nsIWebProgressListener;
  2648.     this.onSecurityChange(null, null, nsIWebProgressListener.STATE_IS_INSECURE);
  2649.   },
  2650.  
  2651.   destroy : function()
  2652.   {
  2653.     // XXXjag to avoid leaks :-/, see bug 60729
  2654.     this.throbberElement = null;
  2655.     this.statusMeter     = null;
  2656.     this.stopCommand     = null;
  2657.     this.statusTextField = null;
  2658.     this.securityButton  = null;
  2659.     this.urlBar          = null;
  2660.     this.statusText      = null;
  2661.     this.lastURI         = null;
  2662.   },
  2663.  
  2664.   setJSStatus : function(status)
  2665.   {
  2666.     this.jsStatus = status;
  2667.     this.updateStatusField();
  2668.   },
  2669.  
  2670.   setJSDefaultStatus : function(status)
  2671.   {
  2672.     this.jsDefaultStatus = status;
  2673.     this.updateStatusField();
  2674.   },
  2675.  
  2676.   setDefaultStatus : function(status)
  2677.   {
  2678.     this.defaultStatus = status;
  2679.     this.updateStatusField();
  2680.   },
  2681.  
  2682.   setOverLink : function(link, b)
  2683.   {
  2684.     this.overLink = link;
  2685.     this.updateStatusField();
  2686.   },
  2687.  
  2688.   updateStatusField : function()
  2689.   {
  2690.     var text = this.overLink || this.status || this.jsStatus || this.jsDefaultStatus || this.defaultStatus;
  2691.  
  2692.     // check the current value so we don't trigger an attribute change
  2693.     // and cause needless (slow!) UI updates
  2694.     if (this.statusText != text) {
  2695.       this.statusTextField.label = text;
  2696.       this.statusText = text;
  2697.     }
  2698.   },
  2699.  
  2700.   onLinkIconAvailable : function(aBrowser, aHref) 
  2701.   {
  2702.     if (gProxyFavIcon &&
  2703.         gBrowser.mCurrentBrowser == aBrowser &&
  2704.         gBrowser.userTypedValue === null)
  2705.     {
  2706.       PageProxySetIcon(aHref);
  2707.     }
  2708.  
  2709.     aBrowser.mFavIconURL = aHref;
  2710.   },
  2711.  
  2712.   onProgressChange : function (aWebProgress, aRequest,
  2713.                                aCurSelfProgress, aMaxSelfProgress,
  2714.                                aCurTotalProgress, aMaxTotalProgress)
  2715.   {
  2716.     if (aMaxTotalProgress > 0) {
  2717.       // This is highly optimized.  Don't touch this code unless
  2718.       // you are intimately familiar with the cost of setting
  2719.       // attrs on XUL elements. -- hyatt
  2720.       var percentage = (aCurTotalProgress * 100) / aMaxTotalProgress;
  2721.       this.statusMeter.value = percentage;
  2722.     } 
  2723.   },
  2724.  
  2725.   onStateChange : function(aWebProgress, aRequest, aStateFlags, aStatus)
  2726.   {  
  2727.     const nsIWebProgressListener = Components.interfaces.nsIWebProgressListener;
  2728.     const nsIChannel = Components.interfaces.nsIChannel;
  2729.     if (aStateFlags & nsIWebProgressListener.STATE_START) {
  2730.         // This (thanks to the filter) is a network start or the first
  2731.         // stray request (the first request outside of the document load),
  2732.         // initialize the throbber and his friends.
  2733.  
  2734.         // always reset the favicon
  2735.         if (gBrowser.mTabbedMode) {
  2736.           var browserIndex = gBrowser.getBrowserIndexForDocument(aWebProgress.DOMWindow);
  2737.           if (browserIndex != -1)
  2738.             gBrowser.getBrowserAtIndex(browserIndex).mFavIconURL = null;
  2739.         }
  2740.         else
  2741.           gBrowser.mCurrentBrowser.mFavIconURL = null;
  2742.  
  2743.         // Call start document load listeners (only if this is a network load)
  2744.         if (aStateFlags & nsIWebProgressListener.STATE_IS_NETWORK &&
  2745.             aRequest && aWebProgress.DOMWindow == content)
  2746.           this.startDocumentLoad(aRequest);
  2747.   
  2748.         if (this.throbberElement) {          
  2749.           // Turn the throbber on.
  2750.           this.throbberElement.setAttribute("busy", "true");
  2751.         }
  2752.  
  2753.         // Turn the status meter on.
  2754.         this.statusMeter.value = 0;  // be sure to clear the progress bar
  2755.         if (gProgressCollapseTimer) {
  2756.           window.clearTimeout(gProgressCollapseTimer);
  2757.           gProgressCollapseTimer = null;
  2758.         }
  2759.         else
  2760.           this.statusMeter.parentNode.collapsed = false;
  2761.  
  2762.         // XXX: This needs to be based on window activity...
  2763.         this.stopCommand.removeAttribute("disabled");
  2764.     }
  2765.     else if (aStateFlags & nsIWebProgressListener.STATE_STOP) {
  2766.       if (aStateFlags & nsIWebProgressListener.STATE_IS_NETWORK) {
  2767.         if (aRequest) {
  2768.           if (aWebProgress.DOMWindow == content)
  2769.             this.endDocumentLoad(aRequest, aStatus);
  2770.         }
  2771.       }
  2772.  
  2773.       // This (thanks to the filter) is a network stop or the last
  2774.       // request stop outside of loading the document, stop throbbers
  2775.       // and progress bars and such
  2776.       if (aRequest) {
  2777.         var msg = "";
  2778.         // Get the channel if the request is a channel
  2779.         var channel;
  2780.         try {
  2781.           channel = aRequest.QueryInterface(nsIChannel);
  2782.         }
  2783.         catch(e) { };
  2784.           if (channel) {
  2785.             var location = channel.URI;
  2786.  
  2787.             // For keyword URIs clear the user typed value since they will be changed into real URIs
  2788.             if (location.scheme == "keyword" && aWebProgress.DOMWindow == content)
  2789.               getBrowser().userTypedValue = null;
  2790.  
  2791.             if (location.spec != "about:blank") {
  2792.               const kErrorBindingAborted = 0x804B0002;
  2793.               const kErrorNetTimeout = 0x804B000E;
  2794.               switch (aStatus) {
  2795.                 case kErrorBindingAborted:
  2796.                   msg = gNavigatorBundle.getString("nv_stopped");
  2797.                   break;
  2798.                 case kErrorNetTimeout:
  2799.                   msg = gNavigatorBundle.getString("nv_timeout");
  2800.                   break;
  2801.               }
  2802.             }
  2803.           }
  2804.           // If msg is false then we did not have an error (channel may have
  2805.           // been null, in the case of a stray image load).
  2806.           if (!msg) {
  2807.             msg = gNavigatorBundle.getString("nv_done");
  2808.           }
  2809.           this.status = "";
  2810.           this.setDefaultStatus(msg);
  2811.         }
  2812.  
  2813.         // Turn the progress meter and throbber off.
  2814.         gProgressCollapseTimer = window.setTimeout(
  2815.           function() { 
  2816.             gProgressMeterPanel.collapsed = true; 
  2817.             gProgressCollapseTimer = null;
  2818.           }, 100);
  2819.  
  2820.         if (this.throbberElement)
  2821.           this.throbberElement.removeAttribute("busy");
  2822.  
  2823.         this.stopCommand.setAttribute("disabled", "true");
  2824.     }
  2825.   },
  2826.  
  2827.   onLocationChange : function(aWebProgress, aRequest, aLocation)
  2828.   {
  2829.     // This code here does not compare uris exactly when determining
  2830.     // whether or not the message should be hidden since the message
  2831.     // may be prematurely hidden when an install is invoked by a click
  2832.     // on a link that looks like this:
  2833.     //
  2834.     // <a href="#" onclick="return install();">Install Foo</a>
  2835.     //
  2836.     // - which fires a onLocationChange message to uri + '#'...
  2837.     var selectedBrowser = getBrowser().selectedBrowser;
  2838.     if (selectedBrowser.lastURI) {
  2839.       var oldSpec = selectedBrowser.lastURI.spec;
  2840.       var oldIndexOfHash = oldSpec.indexOf("#");
  2841.       if (oldIndexOfHash != -1)
  2842.         oldSpec = oldSpec.substr(0, oldIndexOfHash);
  2843.       var newSpec = aLocation.spec;
  2844.       var newIndexOfHash = newSpec.indexOf("#");
  2845.       if (newIndexOfHash != -1)
  2846.         newSpec = newSpec.substr(0, newSpec.indexOf("#"));
  2847.       if (newSpec != oldSpec) {
  2848.         var tabbrowser = getBrowser();
  2849.         tabbrowser.hideMessage(tabbrowser.selectedBrowser, "both");
  2850.       }
  2851.     }
  2852.     selectedBrowser.lastURI = aLocation;
  2853.  
  2854.     this.setOverLink("", null);
  2855.  
  2856.     var location = aLocation.spec;
  2857.  
  2858.     if (location == "about:blank")
  2859.       location = "";
  2860.     
  2861.     // We should probably not do this if the value has changed since the user
  2862.     // searched
  2863.     // Update urlbar only if a new page was loaded on the primary content area
  2864.     // Do not update urlbar if there was a subframe navigation
  2865.  
  2866.     var browser = getBrowser().selectedBrowser;
  2867.     var findField = document.getElementById("find-field");
  2868.     if (aWebProgress.DOMWindow == content) {      
  2869.       // The document loaded correctly, clear the value if we should
  2870.       if (browser.userTypedClear)
  2871.         browser.userTypedValue = null;
  2872.  
  2873.       if (findField)
  2874.         setTimeout(function() { findField.value = browser.findString; }, 0, findField, browser); 
  2875.  
  2876.       //XXXBlake don't we have to reinit this.urlBar, etc.
  2877.       //         when the toolbar changes?
  2878.       if (gURLBar) {
  2879.         var userTypedValue = browser.userTypedValue;
  2880.         if (!userTypedValue) {
  2881.           // If the url has "wyciwyg://" as the protocol, strip it off.
  2882.           // Nobody wants to see it on the urlbar for dynamically generated
  2883.           // pages. 
  2884.           if (!gURIFixup)
  2885.             gURIFixup = Components.classes["@mozilla.org/docshell/urifixup;1"]
  2886.                                   .getService(Components.interfaces.nsIURIFixup);
  2887.           if (location && gURIFixup)
  2888.             try {
  2889.               var locationURI = gURIFixup.createExposableURI(aLocation);
  2890.               location = locationURI.spec;
  2891.             } catch (exception) {}
  2892.  
  2893.           if (getBrowser().forceSyncURLBarUpdate) {
  2894.             gURLBar.value = ""; // hack for bug 249322
  2895.             gURLBar.value = location;
  2896.             SetPageProxyState("valid", aLocation);
  2897.           } else {
  2898.             setTimeout(function(loc, aloc) { 
  2899.                          gURLBar.value = ""; // hack for bug 249322
  2900.                          gURLBar.value = loc; 
  2901.                          SetPageProxyState("valid", aloc);
  2902.                        }, 0, location, aLocation);
  2903.           }
  2904.  
  2905.           // Setting the urlBar value in some cases causes userTypedValue to
  2906.           // become set because of oninput, so reset it to its old value.
  2907.           browser.userTypedValue = userTypedValue;
  2908.         } else {
  2909.           gURLBar.value = userTypedValue;
  2910.           SetPageProxyState("invalid", null);
  2911.         }
  2912.       }
  2913.     }
  2914.     UpdateBackForwardButtons();
  2915.  
  2916.     if (findField && gFindMode != FIND_NORMAL) {
  2917.       // Close the Find toolbar if we're in old-style TAF mode
  2918.       closeFindBar();
  2919.       gBackProtectBuffer = 0;
  2920.     }
  2921.     
  2922.     //fix bug 253793 - turn off highlight when page changes
  2923.     if (document.getElementById("highlight").checked)
  2924.       document.getElementById("highlight").removeAttribute("checked");
  2925.            
  2926.     // clear missing plugins
  2927.     gMissingPluginInstaller.clearMissingPlugins(getBrowser().selectedTab);
  2928.        
  2929.     setTimeout(function () { updatePageLivemarks(); }, 0);
  2930.   },
  2931.  
  2932.   onStatusChange : function(aWebProgress, aRequest, aStatus, aMessage)
  2933.   {
  2934.     this.status = aMessage;
  2935.     this.updateStatusField();
  2936.   },
  2937.  
  2938.   onSecurityChange : function(aWebProgress, aRequest, aState)
  2939.   {
  2940.     const wpl = Components.interfaces.nsIWebProgressListener;
  2941.     this.securityButton.removeAttribute("label");
  2942.  
  2943.     switch (aState) {
  2944.       case wpl.STATE_IS_SECURE | wpl.STATE_SECURE_HIGH:
  2945.         this.securityButton.setAttribute("level", "high");
  2946.         if (this.urlBar)
  2947.           this.urlBar.setAttribute("level", "high");
  2948.         try {
  2949.           this.securityButton.setAttribute("label",
  2950.             gBrowser.contentWindow.location.host);
  2951.         } catch(exception) {}
  2952.         break;
  2953.       case wpl.STATE_IS_SECURE | wpl.STATE_SECURE_LOW:
  2954.         this.securityButton.setAttribute("level", "low");
  2955.         if (this.urlBar)
  2956.           this.urlBar.setAttribute("level", "low");
  2957.         try {
  2958.           this.securityButton.setAttribute("label",
  2959.             gBrowser.contentWindow.location.host);
  2960.         } catch(exception) {}
  2961.         break;
  2962.       case wpl.STATE_IS_BROKEN:
  2963.         this.securityButton.setAttribute("level", "broken");
  2964.         if (this.urlBar)
  2965.           this.urlBar.setAttribute("level", "broken");
  2966.         break;
  2967.       case wpl.STATE_IS_INSECURE:
  2968.       default:
  2969.         this.securityButton.removeAttribute("level");
  2970.         if (this.urlBar)
  2971.           this.urlBar.removeAttribute("level");
  2972.         break;
  2973.     }
  2974.  
  2975.     var securityUI = gBrowser.securityUI;
  2976.     if (securityUI) {
  2977.       this.securityButton.setAttribute("tooltiptext", securityUI.tooltipText);
  2978.       if (this.urlBar)
  2979.         this.urlBar.setAttribute("infotext", securityUI.tooltipText);
  2980.     }
  2981.     else {
  2982.       this.securityButton.setAttribute("tooltiptext", securityUI.tooltipText);
  2983.       if (this.urlBar)
  2984.         this.urlBar.removeAttribute("infotext");
  2985.     }
  2986.   },
  2987.  
  2988.   startDocumentLoad : function(aRequest)
  2989.   {
  2990.     // It's okay to clear what the user typed when we start
  2991.     // loading a document. If the user types, this flag gets
  2992.     // set to false, if the document load ends without an
  2993.     // onLocationChange, this flag also gets set to false
  2994.     // (so we keep it while switching tabs after failed load
  2995.     getBrowser().userTypedClear = true;
  2996.  
  2997.     // clear out livemark data
  2998.     gBrowser.mCurrentBrowser.livemarkLinks = null;
  2999.     
  3000.     const nsIChannel = Components.interfaces.nsIChannel;
  3001.     var urlStr = aRequest.QueryInterface(nsIChannel).URI.spec;
  3002.     var observerService = Components.classes["@mozilla.org/observer-service;1"]
  3003.                                     .getService(Components.interfaces.nsIObserverService);
  3004.     try {
  3005.       observerService.notifyObservers(_content, "StartDocumentLoad", urlStr);
  3006.     } catch (e) {
  3007.     }
  3008.   },
  3009.  
  3010.   endDocumentLoad : function(aRequest, aStatus)
  3011.   {
  3012.     // The document is done loading, it's okay to clear
  3013.     // the value again.
  3014.     getBrowser().userTypedClear = false;
  3015.  
  3016.     const nsIChannel = Components.interfaces.nsIChannel;
  3017.     var urlStr = aRequest.QueryInterface(nsIChannel).originalURI.spec;
  3018.  
  3019.     var observerService = Components.classes["@mozilla.org/observer-service;1"]
  3020.                                     .getService(Components.interfaces.nsIObserverService);
  3021.  
  3022.     var notification = Components.isSuccessCode(aStatus) ? "EndDocumentLoad" : "FailDocumentLoad";
  3023.     try {
  3024.       observerService.notifyObservers(_content, notification, urlStr);
  3025.     } catch (e) {
  3026.     }
  3027.     setTimeout(function() { if (document.getElementById("highlight").checked) toggleHighlight(true); }, 0);
  3028.   }
  3029. }
  3030.  
  3031. function nsBrowserAccess()
  3032. {
  3033. }
  3034.  
  3035. nsBrowserAccess.prototype =
  3036. {
  3037.   QueryInterface : function(aIID)
  3038.   {
  3039.     if (aIID.equals(nsCI.nsIBrowserDOMWindow) ||
  3040.         aIID.equals(nsCI.nsISupports))
  3041.       return this;
  3042.     throw Components.results.NS_NOINTERFACE;
  3043.   },
  3044.  
  3045.   openURI : function(aURI, aOpener, aWhere, aContext)
  3046.   {
  3047.     var newWindow = null;
  3048.     var referrer = null;
  3049.     var isExternal = (aContext == nsCI.nsIBrowserDOMWindow.OPEN_EXTERNAL);
  3050.  
  3051.     if (isExternal && aURI && aURI.schemeIs("chrome"))
  3052.       return null;
  3053.  
  3054.     var loadflags = isExternal ?
  3055.                        nsCI.nsIWebNavigation.LOAD_FLAGS_FROM_EXTERNAL :
  3056.                        nsCI.nsIWebNavigation.LOAD_FLAGS_NONE;
  3057.     if (aWhere == nsCI.nsIBrowserDOMWindow.OPEN_DEFAULTWINDOW) {
  3058.       switch (aContext) {
  3059.         case nsCI.nsIBrowserDOMWindow.OPEN_EXTERNAL :
  3060.           aWhere = gPrefService.getIntPref("browser.link.open_external");
  3061.           break;
  3062.         default : // OPEN_NEW or an illegal value
  3063.           aWhere = gPrefService.getIntPref("browser.link.open_newwindow");
  3064.       }
  3065.     }
  3066.     var url = aURI ? aURI.spec : "about:blank";
  3067.     switch(aWhere) {
  3068.       case nsCI.nsIBrowserDOMWindow.OPEN_NEWWINDOW :
  3069.         newWindow = openDialog(getBrowserURL(), "_blank", "all,dialog=no", url);
  3070.         break;
  3071.       case nsCI.nsIBrowserDOMWindow.OPEN_NEWTAB :
  3072.         var newTab = gBrowser.addTab("about:blank");
  3073.         if (!gPrefService.getBoolPref("browser.tabs.loadDivertedInBackground"))
  3074.           gBrowser.selectedTab = newTab;
  3075.         newWindow = gBrowser.getBrowserForTab(newTab).docShell
  3076.                             .QueryInterface(nsCI.nsIInterfaceRequestor)
  3077.                             .getInterface(nsCI.nsIDOMWindow);
  3078.         try {
  3079.           if (aOpener) {
  3080.             referrer = Components.classes["@mozilla.org/network/standard-url;1"]
  3081.                                  .createInstance(nsCI.nsIURI);
  3082.             referrer.spec = Components.lookupMethod(aOpener,"location")
  3083.                                       .call(aOpener);
  3084.           }
  3085.           newWindow.QueryInterface(nsCI.nsIInterfaceRequestor)
  3086.                    .getInterface(nsCI.nsIWebNavigation)
  3087.                    .loadURI(url, loadflags, referrer, null, null);
  3088.         } catch(e) {
  3089.         }
  3090.         break;
  3091.       default : // OPEN_CURRENTWINDOW or an illegal value
  3092.         try {
  3093.           if (aOpener) {
  3094.             newWindow = Components.lookupMethod(aOpener,"top")
  3095.                                   .call(aOpener);
  3096.             referrer = Components.classes["@mozilla.org/network/standard-url;1"]
  3097.                                  .createInstance(nsCI.nsIURI);
  3098.             referrer.spec = Components.lookupMethod(aOpener,"location")
  3099.                                       .call(aOpener);
  3100.             newWindow.QueryInterface(nsCI.nsIInterfaceRequestor)
  3101.                      .getInterface(nsIWebNavigation)
  3102.                      .loadURI(url, loadflags, referrer, null, null);
  3103.           } else {
  3104.             newWindow = gBrowser.selectedBrowser.docShell
  3105.                                 .QueryInterface(nsCI.nsIInterfaceRequestor)
  3106.                                 .getInterface(nsCI.nsIDOMWindow);
  3107.             getWebNavigation().loadURI(url, loadflags, null, null, null);
  3108.           }
  3109.         } catch(e) {
  3110.         }
  3111.     }
  3112.     return newWindow;
  3113.   }
  3114. }
  3115.  
  3116. function onViewToolbarsPopupShowing(aEvent)
  3117. {
  3118.   var popup = aEvent.target;
  3119.   var i;
  3120.  
  3121.   // Empty the menu
  3122.   for (i = popup.childNodes.length-1; i >= 0; --i) {
  3123.     var deadItem = popup.childNodes[i];
  3124.     if (deadItem.hasAttribute("toolbarindex"))
  3125.       popup.removeChild(deadItem);
  3126.   }
  3127.   
  3128.   var firstMenuItem = popup.firstChild;
  3129.   
  3130.   var toolbox = document.getElementById("navigator-toolbox");
  3131.   for (i = 0; i < toolbox.childNodes.length; ++i) {
  3132.     var toolbar = toolbox.childNodes[i];
  3133.     var toolbarName = toolbar.getAttribute("toolbarname");
  3134.     var type = toolbar.getAttribute("type");
  3135.     if (toolbarName && type != "menubar") {
  3136.       var menuItem = document.createElement("menuitem");
  3137.       menuItem.setAttribute("toolbarindex", i);
  3138.       menuItem.setAttribute("type", "checkbox");
  3139.       menuItem.setAttribute("label", toolbarName);
  3140.       menuItem.setAttribute("accesskey", toolbar.getAttribute("accesskey"));
  3141.       menuItem.setAttribute("checked", toolbar.getAttribute("collapsed") != "true");
  3142.       popup.insertBefore(menuItem, firstMenuItem);        
  3143.       
  3144.       menuItem.addEventListener("command", onViewToolbarCommand, false);
  3145.     }
  3146.     toolbar = toolbar.nextSibling;
  3147.   }
  3148. }
  3149.  
  3150. function onViewToolbarCommand(aEvent)
  3151. {
  3152.   var toolbox = document.getElementById("navigator-toolbox");
  3153.   var index = aEvent.originalTarget.getAttribute("toolbarindex");
  3154.   var toolbar = toolbox.childNodes[index];
  3155.  
  3156.   toolbar.collapsed = aEvent.originalTarget.getAttribute("checked") != "true";
  3157.   document.persist(toolbar.id, "collapsed");
  3158. }
  3159.  
  3160. function displaySecurityInfo()
  3161. {
  3162.   window.openDialog("chrome://browser/content/pageInfo.xul", "_blank",
  3163.                     "dialog=no", null, "securityTab");
  3164. }
  3165.  
  3166. function nsBrowserContentListener(toplevelWindow, contentWindow)
  3167. {
  3168.     // this one is not as easy as you would hope.
  3169.     // need to convert toplevelWindow to an XPConnected object, instead
  3170.     // of a DOM-based object, to be able to QI() it to nsIXULWindow
  3171.     
  3172.     this.init(toplevelWindow, contentWindow);
  3173. }
  3174.  
  3175. /* implements nsIURIContentListener */
  3176.  
  3177. nsBrowserContentListener.prototype =
  3178. {
  3179.     init: function(toplevelWindow, contentWindow)
  3180.     {
  3181.         const nsIWebBrowserChrome = Components.interfaces.nsIWebBrowserChrome;
  3182.         this.toplevelWindow = toplevelWindow;
  3183.         this.contentWindow = contentWindow;
  3184.  
  3185.         // hook up the whole parent chain thing
  3186.         var windowDocShell = this.convertWindowToDocShell(toplevelWindow);
  3187.         if (windowDocShell)
  3188.             windowDocshell.parentURIContentListener = this;
  3189.     
  3190.         var registerWindow = false;
  3191.         try {          
  3192.           var treeItem = contentWindow.docShell.QueryInterface(Components.interfaces.nsIDocShellTreeItem);
  3193.           var treeOwner = treeItem.treeOwner;
  3194.           var interfaceRequestor = treeOwner.QueryInterface(Components.interfaces.nsIInterfaceRequestor);
  3195.           var webBrowserChrome = interfaceRequestor.getInterface(nsIWebBrowserChrome);
  3196.           if (webBrowserChrome)
  3197.           {
  3198.             var chromeFlags = webBrowserChrome.chromeFlags;
  3199.             var res = chromeFlags & nsIWebBrowserChrome.CHROME_ALL;
  3200.             var res2 = chromeFlags & nsIWebBrowserChrome.CHROME_DEFAULT;
  3201.             if ( res == nsIWebBrowserChrome.CHROME_ALL || res2 == nsIWebBrowserChrome.CHROME_DEFAULT)
  3202.             {             
  3203.               registerWindow = true;
  3204.             }
  3205.          }
  3206.        } catch (ex) {} 
  3207.  
  3208.         // register ourselves
  3209.        if (registerWindow)
  3210.        {
  3211.         var uriLoader = Components.classes["@mozilla.org/uriloader;1"].getService(Components.interfaces.nsIURILoader);
  3212.         uriLoader.registerContentListener(this);
  3213.        }
  3214.     },
  3215.     close: function()
  3216.     {
  3217.         this.contentWindow = null;
  3218.         var uriLoader = Components.classes["@mozilla.org/uriloader;1"].getService(Components.interfaces.nsIURILoader);
  3219.  
  3220.         uriLoader.unRegisterContentListener(this);
  3221.     },
  3222.     QueryInterface: function(iid)
  3223.     {
  3224.         if (iid.equals(Components.interfaces.nsIURIContentListener) ||
  3225.             iid.equals(Components.interfaces.nsISupportsWeakReference) ||
  3226.             iid.equals(Components.interfaces.nsISupports))
  3227.           return this;
  3228.         throw Components.results.NS_NOINTERFACE;
  3229.     },
  3230.     onStartURIOpen: function(uri)
  3231.     {
  3232.         // ignore and don't abort
  3233.         return false;
  3234.     },
  3235.  
  3236.     doContent: function(contentType, isContentPreferred, request, contentHandler)
  3237.     {
  3238.         // forward the doContent to our content area webshell
  3239.         var docShell = this.contentWindow.docShell;
  3240.         var contentListener;
  3241.         try {
  3242.             contentListener =
  3243.                 docShell.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
  3244.                 .getInterface(Components.interfaces.nsIURIContentListener);
  3245.         } catch (ex) {
  3246.             dump(ex);
  3247.         }
  3248.         
  3249.         if (!contentListener) return false;
  3250.         
  3251.         return contentListener.doContent(contentType, isContentPreferred, request, contentHandler);
  3252.         
  3253.     },
  3254.  
  3255.     isPreferred: function(contentType, desiredContentType)
  3256.     {
  3257.         // seems like we should be getting this from helper apps or something
  3258.         switch(contentType) {
  3259.             case "text/html":
  3260.             case "text/xul":
  3261.             case "text/rdf":
  3262.             case "text/xml":
  3263.             case "text/css":
  3264.             case "image/gif":
  3265.             case "image/jpeg":
  3266.             case "image/png":
  3267.             case "text/plain":
  3268.             case "application/http-index-format":
  3269.                 return true;
  3270.         }
  3271.         return false;
  3272.     },
  3273.     canHandleContent: function(contentType, isContentPreferred, desiredContentType)
  3274.     {
  3275.         var docShell = this.contentWindow.docShell;
  3276.         var contentListener;
  3277.         try {
  3278.             contentListener =
  3279.                 docShell.QueryInterface(Components.interfaces.nsIInterfaceRequestor).getInterface(Components.interfaces.nsIURIContentListener);
  3280.         } catch (ex) {
  3281.             dump(ex);
  3282.         }
  3283.         if (!contentListener) return false;
  3284.         
  3285.         return contentListener.canHandleContent(contentType, isContentPreferred, desiredContentType);
  3286.     },
  3287.     convertWindowToDocShell: function(win) {
  3288.         // don't know how to do this
  3289.         return null;
  3290.     },
  3291.     loadCookie: null,
  3292.     parentContentListener: null
  3293. }
  3294.  
  3295. // |forceOpen| is a bool that indicates that the sidebar should be forced open.  In other words
  3296. // the toggle won't be allowed to close the sidebar.
  3297. function toggleSidebar(aCommandID, forceOpen) {
  3298.  
  3299.   var sidebarBox = document.getElementById("sidebar-box");
  3300.   if (!aCommandID)
  3301.     aCommandID = sidebarBox.getAttribute("sidebarcommand");
  3302.  
  3303.   var elt = document.getElementById(aCommandID);
  3304.   var sidebar = document.getElementById("sidebar");
  3305.   var sidebarTitle = document.getElementById("sidebar-title");
  3306.   var sidebarSplitter = document.getElementById("sidebar-splitter");
  3307.  
  3308.   if (!forceOpen && elt.getAttribute("checked") == "true") {
  3309.     elt.removeAttribute("checked");
  3310.     sidebarBox.setAttribute("sidebarcommand", "");
  3311.     sidebarTitle.setAttribute("value", "");
  3312.     sidebarBox.hidden = true;
  3313.     sidebarSplitter.hidden = true;
  3314.     _content.focus();
  3315.     return;
  3316.   }
  3317.   
  3318.   var elts = document.getElementsByAttribute("group", "sidebar");
  3319.   for (var i = 0; i < elts.length; ++i)
  3320.     elts[i].removeAttribute("checked");
  3321.  
  3322.   elt.setAttribute("checked", "true");;
  3323.  
  3324.   if (sidebarBox.hidden) {
  3325.     sidebarBox.hidden = false;
  3326.     sidebarSplitter.hidden = false;
  3327.   }
  3328.   
  3329.   var url = elt.getAttribute("sidebarurl");
  3330.   var title = elt.getAttribute("sidebartitle");
  3331.   if (!title)
  3332.     title = elt.getAttribute("label");
  3333.   sidebar.setAttribute("src", url);
  3334.   sidebarBox.setAttribute("src", url);
  3335.   sidebarBox.setAttribute("sidebarcommand", elt.id);
  3336.   sidebarTitle.setAttribute("value", title);
  3337.   if (aCommandID != "viewWebPanelsSidebar") { // no searchbox there
  3338.     // if the sidebar we want is already constructed, focus the searchbox
  3339.     if ((aCommandID == "viewBookmarksSidebar" && sidebar.contentDocument.getElementById("bookmarksPanel"))
  3340.     || (aCommandID == "viewHistorySidebar" && sidebar.contentDocument.getElementById("history-panel")))
  3341.       sidebar.contentDocument.getElementById("search-box").focus();
  3342.     // otherwiese, attach an onload handler
  3343.     else
  3344.       sidebar.addEventListener("load", asyncFocusSearchBox, true);
  3345.   }
  3346. }
  3347.  
  3348. function asyncFocusSearchBox(event)
  3349. {
  3350.   var sidebar = document.getElementById("sidebar");
  3351.   var searchBox = sidebar.contentDocument.getElementById("search-box");
  3352.   searchBox.focus();
  3353.   sidebar.removeEventListener("load", asyncFocusSearchBox, true);
  3354.  }
  3355.  
  3356. function openPreferences()
  3357. {
  3358.   openDialog("chrome://browser/content/pref/pref.xul","PrefWindow", 
  3359.              "chrome,titlebar,resizable,modal");
  3360. }
  3361.  
  3362. var gHomeButton = {
  3363.   prefDomain: "browser.startup.homepage",
  3364.   observe: function (aSubject, aTopic, aPrefName)
  3365.   {
  3366.     if (aTopic != "nsPref:changed" || aPrefName != this.prefDomain)
  3367.       return;
  3368.       
  3369.     this.updateTooltip();
  3370.   },
  3371.   
  3372.   updateTooltip: function ()
  3373.   {
  3374.     var homeButton = document.getElementById("home-button");
  3375.     if (homeButton) {
  3376.       var homePage = this.getHomePage();
  3377.       homePage = homePage.replace(/\|/g,', ');
  3378.       homeButton.setAttribute("tooltiptext", homePage);
  3379.     }
  3380.   },
  3381.     
  3382.   getHomePage: function ()
  3383.   {
  3384.     var url;
  3385.     try {
  3386.       url = gPrefService.getComplexValue(this.prefDomain,
  3387.                                 Components.interfaces.nsIPrefLocalizedString).data;
  3388.     } catch (e) {
  3389.     }
  3390.  
  3391.     // use this if we can't find the pref
  3392.     if (!url) {
  3393.       var navigatorRegionBundle = document.getElementById("bundle_browser_region");
  3394.       url = navigatorRegionBundle.getString("homePageDefault");
  3395.     }
  3396.  
  3397.     return url;
  3398.   }
  3399. };
  3400.  
  3401. function nsContextMenu( xulMenu ) {
  3402.     this.target         = null;
  3403.     this.menu           = null;
  3404.     this.onTextInput    = false;
  3405.     this.onKeywordField = false;
  3406.     this.onImage        = false;
  3407.     this.onLink         = false;
  3408.     this.onMailtoLink   = false;
  3409.     this.onSaveableLink = false;
  3410.     this.onMetaDataItem = false;
  3411.     this.onMathML       = false;
  3412.     this.link           = false;
  3413.     this.inFrame        = false;
  3414.     this.hasBGImage     = false;
  3415.     this.isTextSelected = false;
  3416.     this.inDirList      = false;
  3417.     this.shouldDisplay  = true;
  3418.  
  3419.     // Initialize new menu.
  3420.     this.initMenu( xulMenu );
  3421. }
  3422.  
  3423. // Prototype for nsContextMenu "class."
  3424. nsContextMenu.prototype = {
  3425.     // onDestroy is a no-op at this point.
  3426.     onDestroy : function () {
  3427.     },
  3428.     // Initialize context menu.
  3429.     initMenu : function ( popup ) {
  3430.         // Save menu.
  3431.         this.menu = popup;
  3432.  
  3433.         // Get contextual info.
  3434.         this.setTarget( document.popupNode );
  3435.         
  3436.         this.isTextSelected = this.isTextSelection();
  3437.  
  3438.         // Initialize (disable/remove) menu items.
  3439.         this.initItems();
  3440.     },
  3441.     initItems : function () {
  3442.         this.initOpenItems();
  3443.         this.initNavigationItems();
  3444.         this.initViewItems();
  3445.         this.initMiscItems();
  3446.         this.initSaveItems();
  3447.         this.initClipboardItems();
  3448.         this.initMetadataItems();
  3449.     },
  3450.     initOpenItems : function () {
  3451.         this.showItem( "context-openlink", this.onSaveableLink || ( this.inDirList && this.onLink ) );
  3452.         this.showItem( "context-openlinkintab", this.onSaveableLink || ( this.inDirList && this.onLink ) );
  3453.  
  3454.         this.showItem( "context-sep-open", this.onSaveableLink || ( this.inDirList && this.onLink ) );
  3455.     },
  3456.     initNavigationItems : function () {
  3457.         // Back determined by canGoBack broadcaster.
  3458.         this.setItemAttrFromNode( "context-back", "disabled", "canGoBack" );
  3459.  
  3460.         // Forward determined by canGoForward broadcaster.
  3461.         this.setItemAttrFromNode( "context-forward", "disabled", "canGoForward" );
  3462.         
  3463.         this.showItem( "context-back", !( this.isTextSelected || this.onLink || this.onImage || this.onTextInput ) );
  3464.         this.showItem( "context-forward", !( this.isTextSelected || this.onLink || this.onImage || this.onTextInput ) );
  3465.  
  3466.         this.showItem( "context-reload", !( this.isTextSelected || this.onLink || this.onImage || this.onTextInput ) );
  3467.         
  3468.         this.showItem( "context-stop", !( this.isTextSelected || this.onLink || this.onImage || this.onTextInput ) );
  3469.         this.showItem( "context-sep-stop", !( this.isTextSelected || this.onLink || this.onTextInput || this.onImage ) );
  3470.  
  3471.         // XXX: Stop is determined in navigator.js; the canStop broadcaster is broken
  3472.         //this.setItemAttrFromNode( "context-stop", "disabled", "canStop" );
  3473.     },
  3474.     initSaveItems : function () {
  3475.         this.showItem( "context-savepage", !( this.inDirList || this.isTextSelected || this.onTextInput || this.onLink || this.onImage ));
  3476.         this.showItem( "context-sendpage", !( this.inDirList || this.isTextSelected || this.onTextInput || this.onLink || this.onImage ));
  3477.  
  3478.         // Save link depends on whether we're in a link.
  3479.         this.showItem( "context-savelink", this.onSaveableLink );
  3480.  
  3481.         // Save image depends on whether there is one.
  3482.         this.showItem( "context-saveimage", this.onImage );
  3483.         
  3484.         this.showItem( "context-sendimage", this.onImage );
  3485.         
  3486.         // Send link depends on whether we're in a link.
  3487.         this.showItem( "context-sendlink", this.onSaveableLink );   
  3488.     },
  3489.     initViewItems : function () {
  3490.         // View source is always OK, unless in directory listing.
  3491.         this.showItem( "context-viewpartialsource-selection", this.isTextSelected );
  3492.         this.showItem( "context-viewpartialsource-mathml", this.onMathML && !this.isTextSelected );
  3493.         this.showItem( "context-viewsource", !( this.inDirList || this.onImage || this.isTextSelected || this.onLink || this.onTextInput ) );
  3494.         this.showItem( "context-viewinfo", !( this.inDirList || this.onImage || this.isTextSelected || this.onLink || this.onTextInput ) );
  3495.  
  3496.         this.showItem( "context-sep-properties", !( this.inDirList || this.isTextSelected || this.onTextInput ) );
  3497.         // Set As Wallpaper depends on whether an image was clicked on, and only works if we have a shell service.
  3498.         var haveSetWallpaper = false;
  3499.         // Only enable set as wallpaper if we can get the shell service.
  3500.         var shell = getShellService();
  3501.         if (shell)
  3502.           haveSetWallpaper = true;
  3503.         this.showItem( "context-setWallpaper", haveSetWallpaper && this.onImage );
  3504.  
  3505.         if( haveSetWallpaper && this.onImage ) {
  3506.             // Disable the Set As Wallpaper menu item if we're still trying to load the image or the load failed
  3507.             const nsIImageLoadingContent = Components.interfaces.nsIImageLoadingContent;
  3508.             var disableSetWallpaper = false;
  3509.             if (("complete" in this.target) && !this.target.complete)
  3510.                  disableSetWallpaper = true;
  3511.             else if (this.target instanceof nsIImageLoadingContent) {
  3512.                 var request = this.target.QueryInterface(nsIImageLoadingContent)
  3513.                                   .getRequest(nsIImageLoadingContent.CURRENT_REQUEST);
  3514.                 if (!request)
  3515.                     disableSetWallpaper = true;
  3516.             }
  3517.             else if (makeURL(this.target.src).scheme == "javascript")
  3518.                 disableSetWallpaper = true;
  3519.               
  3520.             this.setItemAttr( "context-setWallpaper", "disabled", disableSetWallpaper);
  3521.         }
  3522.  
  3523.         // View Image depends on whether an image was clicked on.
  3524.         this.showItem( "context-viewimage", this.onImage );
  3525.  
  3526.         // View background image depends on whether there is one.
  3527.         this.showItem( "context-viewbgimage", !( this.inDirList || this.onImage || this.isTextSelected || this.onLink || this.onTextInput ) );
  3528.         this.showItem( "context-sep-viewbgimage", !( this.inDirList || this.onImage || this.isTextSelected || this.onLink || this.onTextInput ) );
  3529.         this.setItemAttr( "context-viewbgimage", "disabled", this.hasBGImage ? null : "true");
  3530.     },
  3531.     initMiscItems : function () {
  3532.         // Use "Bookmark This Link" if on a link.
  3533.         this.showItem( "context-bookmarkpage", !( this.isTextSelected || this.onTextInput || this.onLink || this.onImage ) );
  3534.         this.showItem( "context-bookmarklink", this.onLink && !this.onMailtoLink );
  3535.         this.showItem( "context-searchselect", this.isTextSelected );
  3536.         this.showItem( "context-keywordfield", this.onTextInput && this.onKeywordField );
  3537.         this.showItem( "frame", this.inFrame );
  3538.         this.showItem( "frame-sep", this.inFrame );
  3539.         this.showItem( "context-blockimage", this.onImage);
  3540.  
  3541.         // BiDi UI
  3542.         var showBIDI = isBidiEnabled();
  3543.         this.showItem( "context-sep-bidi", showBIDI);
  3544.         this.showItem( "context-bidi-text-direction-toggle", this.onTextInput && showBIDI);
  3545.         this.showItem( "context-bidi-page-direction-toggle", !this.onTextInput && showBIDI);
  3546.  
  3547.         if (this.onImage) {
  3548.           var blockImage = document.getElementById("context-blockimage");
  3549.  
  3550.           var uri = Components.classes['@mozilla.org/network/standard-url;1'].createInstance(Components.interfaces.nsIURI);
  3551.           uri.spec = this.imageURL;
  3552.  
  3553.           var shortenedUriHost = uri.host.replace(/^www\./i,"");
  3554.           if (shortenedUriHost.length > 15)
  3555.             shortenedUriHost = shortenedUriHost.substr(0,15) + "...";
  3556.           blockImage.label = gNavigatorBundle.getFormattedString ("blockImages", [shortenedUriHost]);
  3557.  
  3558.           if (this.isImageBlocked()) {
  3559.             blockImage.setAttribute("checked", "true");
  3560.           }
  3561.           else
  3562.             blockImage.removeAttribute("checked");
  3563.         }
  3564.     },
  3565.     initClipboardItems : function () {
  3566.  
  3567.         // Copy depends on whether there is selected text.
  3568.         // Enabling this context menu item is now done through the global
  3569.         // command updating system
  3570.         // this.setItemAttr( "context-copy", "disabled", !this.isTextSelected() );
  3571.  
  3572.         goUpdateGlobalEditMenuItems();
  3573.  
  3574.         this.showItem( "context-undo", this.onTextInput );
  3575.         this.showItem( "context-sep-undo", this.onTextInput );
  3576.         this.showItem( "context-cut", this.onTextInput );
  3577.         this.showItem( "context-copy", this.isTextSelected || this.onTextInput );
  3578.         this.showItem( "context-paste", this.onTextInput );
  3579.         this.showItem( "context-delete", this.onTextInput );
  3580.         this.showItem( "context-sep-paste", this.onTextInput );
  3581.         this.showItem( "context-selectall", !( this.onLink || this.onImage ) );
  3582.         this.showItem( "context-sep-selectall", this.isTextSelected );
  3583.  
  3584.         // XXX dr
  3585.         // ------
  3586.         // nsDocumentViewer.cpp has code to determine whether we're
  3587.         // on a link or an image. we really ought to be using that...
  3588.  
  3589.         // Copy email link depends on whether we're on an email link.
  3590.         this.showItem( "context-copyemail", this.onMailtoLink );
  3591.  
  3592.         // Copy link location depends on whether we're on a link.
  3593.         this.showItem( "context-copylink", this.onLink );
  3594.         this.showItem( "context-sep-copylink", this.onLink && this.onImage);
  3595.  
  3596.         // Copy image contents depends on whether we're on an image.
  3597.         this.showItem( "context-copyimage-contents", this.onImage );
  3598.         // Copy image location depends on whether we're on an image.
  3599.         this.showItem( "context-copyimage", this.onImage );
  3600.         this.showItem( "context-sep-copyimage", this.onImage );
  3601.     },
  3602.     initMetadataItems : function () {
  3603.         // Show if user clicked on something which has metadata.
  3604.         this.showItem( "context-metadata", this.onMetaDataItem );
  3605.     },
  3606.     // Set various context menu attributes based on the state of the world.
  3607.     setTarget : function ( node ) {
  3608.         const xulNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
  3609.         if ( node.namespaceURI == xulNS ) {
  3610.           this.shouldDisplay = false;
  3611.           return;
  3612.         }
  3613.         // Initialize contextual info.
  3614.         this.onImage    = false;
  3615.         this.onMetaDataItem = false;
  3616.         this.onTextInput = false;
  3617.         this.onKeywordField = false;
  3618.         this.imageURL   = "";
  3619.         this.onLink     = false;
  3620.         this.onMathML   = false;
  3621.         this.inFrame    = false;
  3622.         this.hasBGImage = false;
  3623.         this.bgImageURL = "";
  3624.  
  3625.         // Remember the node that was clicked.
  3626.         this.target = node;
  3627.  
  3628.         // See if the user clicked on an image.
  3629.         if ( this.target.nodeType == Node.ELEMENT_NODE ) {
  3630.              if ( this.target instanceof HTMLImageElement ) {
  3631.                 this.onImage = true;
  3632.                 this.imageURL = this.target.src;
  3633.                 // Look for image map.
  3634.                 var mapName = this.target.getAttribute( "usemap" );
  3635.                 if ( mapName ) {
  3636.                     // Find map.
  3637.                     var map = this.target.ownerDocument.getElementById( mapName.substr(1) );
  3638.                     if ( map ) {
  3639.                         // Search child <area>s for a match.
  3640.                         var areas = map.childNodes;
  3641.                         //XXX Client side image maps are too hard for now!
  3642.                         areas.length = 0;
  3643.                         for ( var i = 0; i < areas.length && !this.onLink; i++ ) {
  3644.                             var area = areas[i];
  3645.                             if ( area instanceof HTMLAreaElement ) {
  3646.                                 // Get type (rect/circle/polygon/default).
  3647.                                 var type = area.getAttribute( "type" );
  3648.                                 var coords = this.parseCoords( area );
  3649.                                 switch ( type.toUpperCase() ) {
  3650.                                     case "RECT":
  3651.                                     case "RECTANGLE":
  3652.                                         break;
  3653.                                     case "CIRC":
  3654.                                     case "CIRCLE":
  3655.                                         break;
  3656.                                     case "POLY":
  3657.                                     case "POLYGON":
  3658.                                         break;
  3659.                                     case "DEFAULT":
  3660.                                         // Default matches entire image.
  3661.                                         this.onLink = true;
  3662.                                         this.link = area;
  3663.                                         this.onSaveableLink = this.isLinkSaveable( this.link );
  3664.                                         break;
  3665.                                 }
  3666.                             }
  3667.                         }
  3668.                     }
  3669.                 }
  3670.              } else if ( this.target instanceof HTMLObjectElement
  3671.                          &&
  3672.                          // See if object tag is for an image.
  3673.                          this.objectIsImage( this.target ) ) {
  3674.                 // This is an image.
  3675.                 this.onImage = true;
  3676.                 // URL must be constructed.
  3677.                 this.imageURL = this.objectImageURL( this.target );
  3678.              } else if ( this.target instanceof HTMLInputElement) {
  3679.                type = this.target.getAttribute("type");
  3680.                if(type && type.toUpperCase() == "IMAGE") {
  3681.                  this.onImage = true;
  3682.                  // Convert src attribute to absolute URL.
  3683.                  this.imageURL = makeURLAbsolute( this.target.baseURI,
  3684.                                                   this.target.src );
  3685.                } else /* if (this.target.getAttribute( "type" ).toUpperCase() == "TEXT") */ {
  3686.                  this.onTextInput = this.isTargetATextBox(this.target);
  3687.                  this.onKeywordField = this.isTargetAKeywordField(this.target);
  3688.                }
  3689.             } else if ( this.target instanceof HTMLTextAreaElement ) {
  3690.                  this.onTextInput = true;
  3691.             } else if ( this.target instanceof HTMLHtmlElement ) {
  3692.                // pages with multiple <body>s are lame. we'll teach them a lesson.
  3693.                var bodyElt = this.target.ownerDocument.getElementsByTagName("body")[0];
  3694.                if ( bodyElt ) {
  3695.                  var computedURL = this.getComputedURL( bodyElt, "background-image" );
  3696.                  if ( computedURL ) {
  3697.                    this.hasBGImage = true;
  3698.                    this.bgImageURL = makeURLAbsolute( bodyElt.baseURI,
  3699.                                                       computedURL );
  3700.                  }
  3701.                }
  3702.             } else if ( "HTTPIndex" in _content &&
  3703.                         _content.HTTPIndex instanceof Components.interfaces.nsIHTTPIndex ) {
  3704.                 this.inDirList = true;
  3705.                 // Bubble outward till we get to an element with URL attribute
  3706.                 // (which should be the href).
  3707.                 var root = this.target;
  3708.                 while ( root && !this.link ) {
  3709.                     if ( root.tagName == "tree" ) {
  3710.                         // Hit root of tree; must have clicked in empty space;
  3711.                         // thus, no link.
  3712.                         break;
  3713.                     }
  3714.                     if ( root.getAttribute( "URL" ) ) {
  3715.                         // Build pseudo link object so link-related functions work.
  3716.                         this.onLink = true;
  3717.                         this.link = { href : root.getAttribute("URL"),
  3718.                                       getAttribute: function (attr) {
  3719.                                           if (attr == "title") {
  3720.                                               return root.firstChild.firstChild.getAttribute("label");
  3721.                                           } else {
  3722.                                               return "";
  3723.                                           }
  3724.                                       }
  3725.                                     };
  3726.                         // If element is a directory, then you can't save it.
  3727.                         if ( root.getAttribute( "container" ) == "true" ) {
  3728.                             this.onSaveableLink = false;
  3729.                         } else {
  3730.                             this.onSaveableLink = true;
  3731.                         }
  3732.                     } else {
  3733.                         root = root.parentNode;
  3734.                     }
  3735.                 }
  3736.             }
  3737.         }
  3738.  
  3739.         // We have meta data on images.
  3740.         this.onMetaDataItem = this.onImage;
  3741.         
  3742.         // See if the user clicked on MathML
  3743.         const NS_MathML = "http://www.w3.org/1998/Math/MathML";
  3744.         if ((this.target.nodeType == Node.TEXT_NODE &&
  3745.              this.target.parentNode.namespaceURI == NS_MathML)
  3746.              || (this.target.namespaceURI == NS_MathML))
  3747.           this.onMathML = true;
  3748.  
  3749.         // See if the user clicked in a frame.
  3750.         if ( this.target.ownerDocument != window._content.document ) {
  3751.             this.inFrame = true;
  3752.         }
  3753.         
  3754.         // Bubble out, looking for items of interest
  3755.         var elem = this.target;
  3756.         while ( elem ) {
  3757.             if ( elem.nodeType == Node.ELEMENT_NODE ) {
  3758.                 // Link?
  3759.                 if ( !this.onLink && 
  3760.                     ( (elem instanceof HTMLAnchorElement && elem.href) ||
  3761.                       elem instanceof HTMLAreaElement ||
  3762.                       elem instanceof HTMLLinkElement ||
  3763.                       elem.getAttributeNS( "http://www.w3.org/1999/xlink", "type") == "simple" ) ) {
  3764.                     // Clicked on a link.
  3765.                     this.onLink = true;
  3766.                     this.onMetaDataItem = true;
  3767.                     // Remember corresponding element.
  3768.                     this.link = elem;
  3769.                     this.onMailtoLink = this.isLinkType( "mailto:", this.link );
  3770.                     // Remember if it is saveable.
  3771.                     this.onSaveableLink = this.isLinkSaveable( this.link );
  3772.                 }
  3773.                 
  3774.                 // Text input?
  3775.                 if ( !this.onTextInput ) {
  3776.                     // Clicked on a link.
  3777.                     this.onTextInput = this.isTargetATextBox(elem);
  3778.                 }
  3779.                 
  3780.                 // Metadata item?
  3781.                 if ( !this.onMetaDataItem ) {
  3782.                     // We currently display metadata on anything which fits
  3783.                     // the below test.
  3784.                     if ( ( elem instanceof HTMLQuoteElement && elem.cite)    ||
  3785.                          ( elem instanceof HTMLTableElement && elem.summary) ||
  3786.                          ( elem instanceof HTMLModElement &&
  3787.                              ( elem.cite || elem.dateTime ) )                ||
  3788.                          ( elem instanceof HTMLElement &&
  3789.                              ( elem.title || elem.lang ) ) ) {
  3790.                         this.onMetaDataItem = true;
  3791.                     }
  3792.                 }
  3793.  
  3794.                 // Background image?  Don't bother if we've already found a 
  3795.                 // background image further down the hierarchy.  Otherwise,
  3796.                 // we look for the computed background-image style.
  3797.                 if ( !this.hasBGImage ) {
  3798.                     var bgImgUrl = this.getComputedURL( elem, "background-image" );
  3799.                     if ( bgImgUrl ) {
  3800.                         this.hasBGImage = true;
  3801.                         this.bgImageURL = makeURLAbsolute( elem.baseURI,
  3802.                                                            bgImgUrl );
  3803.                     }
  3804.                 }
  3805.             }
  3806.             elem = elem.parentNode;    
  3807.         }
  3808.     },
  3809.     // Returns the computed style attribute for the given element.
  3810.     getComputedStyle: function( elem, prop ) {
  3811.          return elem.ownerDocument.defaultView.getComputedStyle( elem, '' ).getPropertyValue( prop );
  3812.     },
  3813.     // Returns a "url"-type computed style attribute value, with the url() stripped.
  3814.     getComputedURL: function( elem, prop ) {
  3815.          var url = elem.ownerDocument.defaultView.getComputedStyle( elem, '' ).getPropertyCSSValue( prop );
  3816.          return ( url.primitiveType == CSSPrimitiveValue.CSS_URI ) ? url.getStringValue() : null;
  3817.     },
  3818.     // Returns true iff clicked on link is saveable.
  3819.     isLinkSaveable : function ( link ) {
  3820.         // We don't do the Right Thing for news/snews yet, so turn them off
  3821.         // until we do.
  3822.         return !(this.isLinkType( "mailto:" , link )     ||
  3823.                  this.isLinkType( "javascript:" , link ) ||
  3824.                  this.isLinkType( "news:", link )        || 
  3825.                  this.isLinkType( "snews:", link ) ); 
  3826.     },
  3827.     // Returns true iff clicked on link is of type given.
  3828.     isLinkType : function ( linktype, link ) {        
  3829.         try {
  3830.             // Test for missing protocol property.
  3831.             if ( !link.protocol ) {
  3832.                 // We must resort to testing the URL string :-(.
  3833.                 var protocol;
  3834.                 var wrapper = new XPCNativeWrapper(link, "href",
  3835.                                                    "getAttributeNS()");
  3836.                 if (wrapper.href) {
  3837.                     protocol = wrapper.href.substr(0, linktype.length);
  3838.                 } else {
  3839.                     protocol = wrapper.getAttributeNS("http://www.w3.org/1999/xlink","href");
  3840.                     if (protocol) {
  3841.                         protocol = protocol.substr(0, linktype.length);
  3842.                     }
  3843.                 }
  3844.                 return protocol.toLowerCase() === linktype;        
  3845.             } else {
  3846.                 // Presume all but javascript: urls are saveable.
  3847.                 return link.protocol.toLowerCase() === linktype;
  3848.             }
  3849.         } catch (e) {
  3850.             // something was wrong with the link,
  3851.             // so we won't be able to save it anyway
  3852.             return false;
  3853.         }
  3854.     },
  3855.     // Open linked-to URL in a new window.
  3856.     openLink : function () {
  3857.         // Determine linked-to URL.
  3858.         openNewWindowWith(this.linkURL(), this.link, true);
  3859.     },
  3860.     // Open linked-to URL in a new tab.
  3861.     openLinkInTab : function () {
  3862.         // Determine linked-to URL.
  3863.         openNewTabWith(this.linkURL(), this.link, null, true);
  3864.     },
  3865.     // Open frame in a new tab.
  3866.     openFrameInTab : function () {
  3867.         // Determine linked-to URL.
  3868.         openNewTabWith(this.target.ownerDocument.location.href, null, null, true);
  3869.     },
  3870.     // Reload clicked-in frame.
  3871.     reloadFrame : function () {
  3872.         this.target.ownerDocument.location.reload();
  3873.     },
  3874.     // Open clicked-in frame in its own window.
  3875.     openFrame : function () {
  3876.         openNewWindowWith(this.target.ownerDocument.location.href, null, true);
  3877.     },
  3878.     // Open clicked-in frame in the same window
  3879.     showOnlyThisFrame : function () {
  3880.         window.loadURI(this.target.ownerDocument.location.href, null, null);
  3881.     },
  3882.     // View Partial Source
  3883.     viewPartialSource : function ( context ) {
  3884.         var focusedWindow = document.commandDispatcher.focusedWindow;
  3885.         if (focusedWindow == window)
  3886.           focusedWindow = _content;
  3887.         var docCharset = null;
  3888.         if (focusedWindow)
  3889.           docCharset = "charset=" + focusedWindow.document.characterSet;
  3890.  
  3891.         // "View Selection Source" and others such as "View MathML Source"
  3892.         // are mutually exclusive, with the precedence given to the selection
  3893.         // when there is one
  3894.         var reference = null;
  3895.         if (context == "selection")
  3896.           reference = focusedWindow.getSelection();
  3897.         else if (context == "mathml")
  3898.           reference = this.target;
  3899.         else
  3900.           throw "not reached";
  3901.  
  3902.         var docUrl = null; // unused (and play nice for fragments generated via XSLT too)
  3903.         window.openDialog("chrome://global/content/viewPartialSource.xul",
  3904.                           "_blank", "scrollbars,resizable,chrome,dialog=no",
  3905.                           docUrl, docCharset, reference, context);
  3906.     },
  3907.     // Open new "view source" window with the frame's URL.
  3908.     viewFrameSource : function () {
  3909.         BrowserViewSourceOfDocument(this.target.ownerDocument);
  3910.     },
  3911.     viewInfo : function () {
  3912.       BrowserPageInfo();
  3913.     },
  3914.     viewFrameInfo : function () {
  3915.       BrowserPageInfo(this.target.ownerDocument);
  3916.     },
  3917.     // Change current window to the URL of the image.
  3918.     viewImage : function (e) {
  3919.         urlSecurityCheck( this.imageURL, document )
  3920.         openUILink( this.imageURL, e );
  3921.     },
  3922.     // Change current window to the URL of the background image.
  3923.     viewBGImage : function (e) {
  3924.         urlSecurityCheck( this.bgImageURL, document )
  3925.         openUILink( this.bgImageURL, e );
  3926.     },
  3927.     setWallpaper: function() {
  3928.       // Confirm since it's annoying if you hit this accidentally.
  3929.       openDialog("chrome://browser/content/setWallpaper.xul", "",
  3930.                  "centerscreen,chrome,dialog,modal,dependent",
  3931.                  this.target);
  3932.     },    
  3933.     // Save URL of clicked-on frame.
  3934.     saveFrame : function () {
  3935.         saveDocument( this.target.ownerDocument );
  3936.     },
  3937.     // Save URL of clicked-on link.
  3938.     saveLink : function () {
  3939.         saveURL( this.linkURL(), this.linkText(), null, true, false );
  3940.     },
  3941.     sendLink : function () {
  3942.         MailIntegration.sendMessage( this.linkURL(), "" ); // we don't know the title of the link so pass in an empty string
  3943.     },
  3944.     // Save URL of clicked-on image.
  3945.     saveImage : function () {
  3946.         saveURL( this.imageURL, null, "SaveImageTitle", false );
  3947.     },
  3948.     sendImage : function () {
  3949.         MailIntegration.sendMessage(this.imageURL, "");
  3950.     },
  3951.     toggleImageBlocking : function (aBlock) {
  3952.       var nsIPermissionManager = Components.interfaces.nsIPermissionManager;
  3953.       var permissionmanager =
  3954.         Components.classes["@mozilla.org/permissionmanager;1"]
  3955.           .getService(nsIPermissionManager);
  3956.       var uri = Components.classes["@mozilla.org/network/standard-url;1"]
  3957.                           .createInstance(Components.interfaces.nsIURI);
  3958.       uri.spec = this.imageURL;
  3959.       permissionmanager.add(uri, "image",
  3960.                             aBlock ? nsIPermissionManager.DENY_ACTION : nsIPermissionManager.ALLOW_ACTION);
  3961.     },
  3962.     isImageBlocked : function() {
  3963.       var nsIPermissionManager = Components.interfaces.nsIPermissionManager;
  3964.       var permissionmanager =
  3965.         Components.classes["@mozilla.org/permissionmanager;1"]
  3966.           .getService(Components.interfaces.nsIPermissionManager);
  3967.       var uri = Components.classes["@mozilla.org/network/standard-url;1"]
  3968.                           .createInstance(Components.interfaces.nsIURI);
  3969.       uri.spec = this.imageURL;
  3970.       return permissionmanager.testPermission(uri, "image") == nsIPermissionManager.DENY_ACTION;
  3971.     },
  3972.     // Generate email address and put it on clipboard.
  3973.     copyEmail : function () {
  3974.         // Copy the comma-separated list of email addresses only.
  3975.         // There are other ways of embedding email addresses in a mailto:
  3976.         // link, but such complex parsing is beyond us.
  3977.         var url = this.linkURL();
  3978.         var qmark = url.indexOf( "?" );
  3979.         var addresses;
  3980.         
  3981.         if ( qmark > 7 ) {                   // 7 == length of "mailto:"
  3982.             addresses = url.substring( 7, qmark );
  3983.         } else {
  3984.             addresses = url.substr( 7 );
  3985.         }
  3986.  
  3987.         // Let's try to unescape it using a character set
  3988.         // in case the address is not ASCII.
  3989.         try {
  3990.           var characterSet = Components.lookupMethod(this.target.ownerDocument, "characterSet")
  3991.                                        .call(this.target.ownerDocument);
  3992.           const textToSubURI = Components.classes["@mozilla.org/intl/texttosuburi;1"]
  3993.                                          .getService(Components.interfaces.nsITextToSubURI);
  3994.           addresses = textToSubURI.unEscapeNonAsciiURI(characterSet, addresses);
  3995.         }
  3996.         catch(ex) {
  3997.           // Do nothing.
  3998.         }
  3999.  
  4000.         var clipboard = this.getService( "@mozilla.org/widget/clipboardhelper;1",
  4001.                                          Components.interfaces.nsIClipboardHelper );
  4002.         clipboard.copyString(addresses);
  4003.     },    
  4004.     addBookmark : function() {
  4005.       var docshell = document.getElementById( "content" ).webNavigation;
  4006.       BookmarksUtils.addBookmark( docshell.currentURI.spec,
  4007.                                   docshell.document.title,
  4008.                                   docshell.document.charset);
  4009.     },
  4010.     addBookmarkForFrame : function() {
  4011.       var doc = this.target.ownerDocument;
  4012.       var uri = doc.location.href;
  4013.       var title = doc.title;
  4014.       if ( !title )
  4015.         title = uri;
  4016.       BookmarksUtils.addBookmark(uri, title, doc.charset);
  4017.     },
  4018.     // Open Metadata window for node
  4019.     showMetadata : function () {
  4020.         window.openDialog(  "chrome://browser/content/metaData.xul",
  4021.                             "_blank",
  4022.                             "scrollbars,resizable,chrome,dialog=no",
  4023.                             this.target);
  4024.     },
  4025.  
  4026.     ///////////////
  4027.     // Utilities //
  4028.     ///////////////
  4029.  
  4030.     // Create instance of component given contractId and iid (as string).
  4031.     createInstance : function ( contractId, iidName ) {
  4032.         var iid = Components.interfaces[ iidName ];
  4033.         return Components.classes[ contractId ].createInstance( iid );
  4034.     },
  4035.     // Get service given contractId and iid (as string).
  4036.     getService : function ( contractId, iidName ) {
  4037.         var iid = Components.interfaces[ iidName ];
  4038.         return Components.classes[ contractId ].getService( iid );
  4039.     },
  4040.     // Show/hide one item (specified via name or the item element itself).
  4041.     showItem : function ( itemOrId, show ) {
  4042.         var item = itemOrId.constructor == String ? document.getElementById(itemOrId) : itemOrId;
  4043.         if (item) 
  4044.           item.hidden = !show;
  4045.     },
  4046.     // Set given attribute of specified context-menu item.  If the
  4047.     // value is null, then it removes the attribute (which works
  4048.     // nicely for the disabled attribute).
  4049.     setItemAttr : function ( id, attr, val ) {
  4050.         var elem = document.getElementById( id );
  4051.         if ( elem ) {
  4052.             if ( val == null ) {
  4053.                 // null indicates attr should be removed.
  4054.                 elem.removeAttribute( attr );
  4055.             } else {
  4056.                 // Set attr=val.
  4057.                 elem.setAttribute( attr, val );
  4058.             }
  4059.         }
  4060.     },
  4061.     // Set context menu attribute according to like attribute of another node
  4062.     // (such as a broadcaster).
  4063.     setItemAttrFromNode : function ( item_id, attr, other_id ) {
  4064.         var elem = document.getElementById( other_id );
  4065.         if ( elem && elem.getAttribute( attr ) == "true" ) {
  4066.             this.setItemAttr( item_id, attr, "true" );
  4067.         } else {
  4068.             this.setItemAttr( item_id, attr, null );
  4069.         }
  4070.     },
  4071.     // Temporary workaround for DOM api not yet implemented by XUL nodes.
  4072.     cloneNode : function ( item ) {
  4073.         // Create another element like the one we're cloning.
  4074.         var node = document.createElement( item.tagName );
  4075.  
  4076.         // Copy attributes from argument item to the new one.
  4077.         var attrs = item.attributes;
  4078.         for ( var i = 0; i < attrs.length; i++ ) {
  4079.             var attr = attrs.item( i );
  4080.             node.setAttribute( attr.nodeName, attr.nodeValue );
  4081.         }
  4082.  
  4083.         // Voila!
  4084.         return node;
  4085.     },
  4086.     // Generate fully-qualified URL for clicked-on link.
  4087.     linkURL : function () {
  4088.         var wrapper = new XPCNativeWrapper(this.link, "href", "baseURI",
  4089.                                            "getAttributeNS()");
  4090.         if (wrapper.href) {
  4091.           return wrapper.href;
  4092.         }
  4093.         var href = wrapper.getAttributeNS("http://www.w3.org/1999/xlink",
  4094.                                           "href");
  4095.         if (!href || !href.match(/\S/)) {
  4096.           throw "Empty href"; // Without this we try to save as the current doc, for example, HTML case also throws if empty
  4097.         }
  4098.         href = makeURLAbsolute(wrapper.baseURI, href);
  4099.         return href;
  4100.     },
  4101.     // Get text of link.
  4102.     linkText : function () {
  4103.         var text = gatherTextUnder( this.link );
  4104.         if (!text || !text.match(/\S/)) {
  4105.           text = this.link.getAttribute("title");
  4106.           if (!text || !text.match(/\S/)) {
  4107.             text = this.link.getAttribute("alt");
  4108.             if (!text || !text.match(/\S/)) {
  4109.               var wrapper = new XPCNativeWrapper(this.link, "href", "baseURI",
  4110.                                                  "getAttributeNS()");
  4111.  
  4112.               if (wrapper.href) {
  4113.                 text = wrapper.href;
  4114.               } else {
  4115.                 text = wrapper.getAttributeNS("http://www.w3.org/1999/xlink",
  4116.                                               "href");
  4117.                 if (text && text.match(/\S/)) {
  4118.                   text = makeURLAbsolute(wrapper.baseURI, text);
  4119.                 }
  4120.               }
  4121.             }
  4122.           }
  4123.         }
  4124.  
  4125.         return text;
  4126.     },
  4127.  
  4128.     //Get selected object and convert it to a string to get
  4129.     //selected text.   Only use the first 15 chars.
  4130.     isTextSelection : function() {
  4131.         var result = false;
  4132.         var selection = this.searchSelected(16);
  4133.  
  4134.         var searchSelectText;
  4135.         if (selection) {
  4136.             searchSelectText = selection.toString();
  4137.             if (searchSelectText.length > 15)
  4138.                 searchSelectText = searchSelectText.substr(0,15) + "...";
  4139.             result = true;
  4140.  
  4141.           // format "Search for <selection>" string to show in menu
  4142.           searchSelectText = gNavigatorBundle.getFormattedString("searchText", [searchSelectText]);
  4143.           this.setItemAttr("context-searchselect", "label", searchSelectText);
  4144.         } 
  4145.         return result;
  4146.     },
  4147.     
  4148.     searchSelected : function( charlen ) {
  4149.         var focusedWindow = document.commandDispatcher.focusedWindow;
  4150.         var searchStr = focusedWindow.getSelection();
  4151.         searchStr = searchStr.toString();
  4152.         // searching for more than 150 chars makes no sense
  4153.         if (!charlen)
  4154.             charlen = 150;
  4155.         if (charlen < searchStr.length) {
  4156.             // only use the first charlen important chars. see bug 221361
  4157.             var pattern = new RegExp("^(?:\\s*.){0," + charlen + "}");
  4158.             pattern.test(searchStr);
  4159.             searchStr = RegExp.lastMatch;
  4160.         }
  4161.         searchStr = searchStr.replace(/\s*(.*?)\s*$/, "$1");
  4162.         searchStr = searchStr.replace(/\s+/g, " ");
  4163.         return searchStr;
  4164.     },
  4165.     
  4166.     // Determine if target <object> is an image.
  4167.     objectIsImage : function ( objElem ) {
  4168.         var result = false;
  4169.         // Get type and data attributes.
  4170.         var type = objElem.getAttribute( "type" );
  4171.         var data = objElem.getAttribute( "data" );
  4172.         // Presume any mime type of the form "image/..." is an image.
  4173.         // There must be a data= attribute with an URL, also.
  4174.         if ( type.substring( 0, 6 ) == "image/" && data) {
  4175.             result = true;
  4176.         }
  4177.         return result;
  4178.     },
  4179.     // Extract image URL from <object> tag.
  4180.     objectImageURL : function ( objElem ) {
  4181.         // Extract url from data= attribute.
  4182.         var data = objElem.getAttribute( "data" );
  4183.         // Make it absolute.
  4184.         return makeURLAbsolute( objElem.baseURI, data );
  4185.     },
  4186.     // Parse coords= attribute and return array.
  4187.     parseCoords : function ( area ) {
  4188.         return [];
  4189.     },
  4190.     toString : function () {
  4191.         return "contextMenu.target     = " + this.target + "\n" +
  4192.                "contextMenu.onImage    = " + this.onImage + "\n" +
  4193.                "contextMenu.onLink     = " + this.onLink + "\n" +
  4194.                "contextMenu.link       = " + this.link + "\n" +
  4195.                "contextMenu.inFrame    = " + this.inFrame + "\n" +
  4196.                "contextMenu.hasBGImage = " + this.hasBGImage + "\n";
  4197.     },
  4198.     isTargetATextBox : function ( node )
  4199.     {
  4200.       if (node instanceof HTMLInputElement)
  4201.         return (node.type == "text" || node.type == "password")
  4202.  
  4203.       return (node instanceof HTMLTextAreaElement);
  4204.     },
  4205.     isTargetAKeywordField : function ( node )
  4206.     {
  4207.       var form = node.form;
  4208.       if (!form)
  4209.         return false;
  4210.       var method = form.method.toUpperCase();
  4211.       
  4212.       // These are the following types of forms we can create keywords for:
  4213.       //
  4214.       // method   encoding type       can create keyword
  4215.       // GET      *                                 YES
  4216.       //          *                                 YES
  4217.       // POST                                       YES
  4218.       // POST     application/x-www-form-urlencoded YES
  4219.       // POST     text/plain                        NO (a little tricky to do)
  4220.       // POST     multipart/form-data               NO
  4221.       // POST     everything else                   YES
  4222.       return (method == "GET" || method == "") || 
  4223.              (form.enctype != "text/plain") && (form.enctype != "multipart/form-data");
  4224.     },
  4225.     
  4226.     // Determines whether or not the separator with the specified ID should be 
  4227.     // shown or not by determining if there are any non-hidden items between it
  4228.     // and the previous separator. 
  4229.     shouldShowSeparator : function ( aSeparatorID )
  4230.     {
  4231.       var separator = document.getElementById(aSeparatorID);
  4232.       if (separator) {
  4233.         var sibling = separator.previousSibling;
  4234.         while (sibling && sibling.localName != "menuseparator") {
  4235.           if (sibling.getAttribute("hidden") != "true")
  4236.             return true;
  4237.           sibling = sibling.previousSibling;
  4238.         }
  4239.       }
  4240.       return false;  
  4241.     }
  4242. }
  4243.  
  4244. var gWebPanelURI;
  4245. function openWebPanel(aTitle, aURI)
  4246. {
  4247.     // Ensure that the web panels sidebar is open.
  4248.     toggleSidebar('viewWebPanelsSidebar', true);
  4249.     
  4250.     // Set the title of the panel.
  4251.     document.getElementById("sidebar-title").value = aTitle;
  4252.     
  4253.     // Tell the Web Panels sidebar to load the bookmark.
  4254.     var sidebar = document.getElementById("sidebar");
  4255.     if (sidebar.contentDocument && sidebar.contentDocument.getElementById('web-panels-browser')) {
  4256.         sidebar.contentWindow.loadWebPanel(aURI);
  4257.         if (gWebPanelURI) {
  4258.             gWebPanelURI = "";
  4259.             sidebar.removeEventListener("load", asyncOpenWebPanel, true);
  4260.         }
  4261.     }
  4262.     else {
  4263.         // The panel is still being constructed.  Attach an onload handler.
  4264.         if (!gWebPanelURI)
  4265.             sidebar.addEventListener("load", asyncOpenWebPanel, true);
  4266.         gWebPanelURI = aURI;
  4267.     }
  4268. }
  4269.  
  4270. function asyncOpenWebPanel(event)
  4271. {
  4272.     var sidebar = document.getElementById("sidebar");
  4273.     if (gWebPanelURI && sidebar.contentDocument && sidebar.contentDocument.getElementById('web-panels-browser'))
  4274.         sidebar.contentWindow.loadWebPanel(gWebPanelURI);
  4275.     gWebPanelURI = "";
  4276.     sidebar.removeEventListener("load", asyncOpenWebPanel, true);
  4277. }
  4278.  
  4279. /*
  4280.  * - [ Dependencies ] ---------------------------------------------------------
  4281.  *  utilityOverlay.js:
  4282.  *    - gatherTextUnder
  4283.  */
  4284.  
  4285.  // Called whenever the user clicks in the content area,
  4286.  // except when left-clicking on links (special case)
  4287.  // should always return true for click to go through
  4288.  function contentAreaClick(event, fieldNormalClicks) 
  4289.  {
  4290.    if (!event.isTrusted) {
  4291.      return true;
  4292.    }
  4293.  
  4294.    var target = event.target;
  4295.    var linkNode;
  4296.  
  4297.    if (target instanceof HTMLAnchorElement ||
  4298.        target instanceof HTMLAreaElement ||
  4299.        target instanceof HTMLLinkElement) {
  4300.      if (target.hasAttribute("href"))
  4301.        linkNode = target;
  4302.    }
  4303.    else {
  4304.      linkNode = event.originalTarget;
  4305.      while (linkNode && !(linkNode instanceof HTMLAnchorElement))
  4306.        linkNode = linkNode.parentNode;
  4307.      // <a> cannot be nested.  So if we find an anchor without an
  4308.      // href, there is no useful <a> around the target
  4309.      if (linkNode && !linkNode.hasAttribute("href"))
  4310.        linkNode = null;
  4311.    }
  4312.    if (linkNode) {
  4313.      var wrapper = new XPCNativeWrapper(linkNode, "href", "getAttribute()", "ownerDocument");
  4314.      if (event.button == 0 && !event.ctrlKey && !event.shiftKey &&
  4315.          !event.altKey && !event.metaKey) {
  4316.        // A Web panel's links should target the main content area.  Do this
  4317.        // if no modifier keys are down and if there's no target or the target equals
  4318.        // _main (the IE convention) or _content (the Mozilla convention).
  4319.        // The only reason we field _main and _content here is for the markLinkVisited
  4320.        // hack.
  4321.        target = wrapper.getAttribute("target");
  4322.        var docWrapper = new XPCNativeWrapper(wrapper.ownerDocument, "location");
  4323.        var locWrapper = new XPCNativeWrapper(docWrapper.location, "href");
  4324.        if (fieldNormalClicks && 
  4325.            (!target || target == "_content" || target  == "_main")) 
  4326.          // IE uses _main, SeaMonkey uses _content, we support both
  4327.        {
  4328.          if (!wrapper.href) 
  4329.            return true;
  4330.          if (wrapper.getAttribute("onclick")) 
  4331.            return true;
  4332.          // javascript links should be executed in the current browser
  4333.          if (wrapper.href.substr(0, 11) === "javascript:")
  4334.            return true;
  4335.          // data links should be executed in the current browser
  4336.          if (wrapper.href.substr(0, 5) === "data:")
  4337.            return true;
  4338.  
  4339.          if (!webPanelSecurityCheck(locWrapper.href, wrapper.href))
  4340.            return false;
  4341.  
  4342.          var postData = { };
  4343.          var url = getShortcutOrURI(wrapper.href, postData);
  4344.          if (!url)
  4345.            return true;
  4346.          markLinkVisited(wrapper.href, linkNode);
  4347.          loadURI(url, null, postData.value);
  4348.          event.preventDefault();
  4349.          return false;
  4350.        }
  4351.        else if (linkNode.getAttribute("rel") == "sidebar") {
  4352.          // This is the Opera convention for a special link that - when clicked - allows
  4353.          // you to add a sidebar panel.  We support the Opera convention here.  The link's
  4354.          // title attribute contains the title that should be used for the sidebar panel.
  4355.          openDialog("chrome://browser/content/bookmarks/addBookmark2.xul", "",
  4356.                     "centerscreen,chrome,dialog,resizable,dependent",
  4357.                     wrapper.getAttribute("title"), 
  4358.                     wrapper.href, null, null, null, null, true);
  4359.          event.preventDefault();
  4360.          return false;
  4361.        }
  4362.        else if (target == "_search") {
  4363.          // Used in WinIE as a way of transiently loading pages in a sidebar.  We
  4364.          // mimic that WinIE functionality here and also load the page transiently.
  4365.  
  4366.          // javascript links targeting the sidebar shouldn't be allowed
  4367.          // we copied this from IE, and IE blocks this completely
  4368.          if (wrapper.href.substr(0, 11) === "javascript:")
  4369.            return false;
  4370.  
  4371.          // data: URIs are just as dangerous
  4372.          if (wrapper.href.substr(0, 5) === "data:")
  4373.            return false;
  4374.  
  4375.          if (!webPanelSecurityCheck(locWrapper.href, wrapper.href))
  4376.            return false;
  4377.  
  4378.          openWebPanel(gNavigatorBundle.getString("webPanels"), wrapper.href);
  4379.          event.preventDefault();
  4380.          return false;
  4381.        }
  4382.      }
  4383.      else {
  4384.        handleLinkClick(event, wrapper.href, linkNode);
  4385.      }
  4386.  
  4387.      return true;
  4388.    } else {
  4389.      // Try simple XLink
  4390.      var href;
  4391.      linkNode = target;
  4392.      while (linkNode) {
  4393.        if (linkNode.nodeType == Node.ELEMENT_NODE) {
  4394.          var wrapper = new XPCNativeWrapper(linkNode, "getAttributeNS()");
  4395.  
  4396.          href = wrapper.getAttributeNS("http://www.w3.org/1999/xlink", "href");
  4397.          break;
  4398.        }
  4399.        linkNode = linkNode.parentNode;
  4400.      }
  4401.      if (href) {
  4402.        var baseURI = new XPCNativeWrapper(linkNode, "baseURI").baseURI;
  4403.        href = makeURLAbsolute(baseURI, href);
  4404.        handleLinkClick(event, href, null);
  4405.        return true;
  4406.      }
  4407.    }
  4408.    if (event.button == 1 &&
  4409.        !event.getPreventDefault() &&
  4410.        gPrefService.getBoolPref("middlemouse.contentLoadURL")) {
  4411.      middleMousePaste(event);
  4412.    }
  4413.    return true;
  4414.  }
  4415.  
  4416. function handleLinkClick(event, href, linkNode)
  4417. {
  4418.   switch (event.button) {                                   
  4419.     case 0:
  4420.       if (event.ctrlKey) {
  4421.         openNewTabWith(href, linkNode, event, true);
  4422.         event.preventBubble();
  4423.         return true;
  4424.       } 
  4425.                                                        // if left button clicked
  4426.       if (event.shiftKey) {
  4427.         openNewWindowWith(href, linkNode, true);
  4428.         event.preventBubble();
  4429.         return true;
  4430.       }
  4431.       
  4432.       if (event.altKey) {
  4433.         saveURL(href, linkNode ? gatherTextUnder(linkNode) : "", null, true, true);
  4434.         return true;
  4435.       }
  4436.  
  4437.       return false;
  4438.     case 1:                                                         // if middle button clicked
  4439.       var tab;
  4440.       try {
  4441.         tab = gPrefService.getBoolPref("browser.tabs.opentabfor.middleclick")
  4442.       }
  4443.       catch(ex) {
  4444.         tab = true;
  4445.       }
  4446.       if (tab)
  4447.         openNewTabWith(href, linkNode, event, true);
  4448.       else
  4449.         openNewWindowWith(href, linkNode, true);
  4450.       event.preventBubble();
  4451.       return true;
  4452.   }
  4453.   return false;
  4454. }
  4455.  
  4456. function middleMousePaste(event)
  4457. {
  4458.   var url = readFromClipboard();
  4459.   if (!url)
  4460.     return;
  4461.   var postData = { };
  4462.   url = getShortcutOrURI(url, postData);
  4463.   if (!url)
  4464.     return;
  4465.  
  4466.   openUILink(url,
  4467.              event,
  4468.              true /* ignore the fact this is a middle click */);
  4469.  
  4470.   event.preventBubble();
  4471. }
  4472.  
  4473. function makeURLAbsolute( base, url ) 
  4474. {
  4475.   // Construct nsIURL.
  4476.   var ioService = Components.classes["@mozilla.org/network/io-service;1"]
  4477.                 .getService(Components.interfaces.nsIIOService);
  4478.   var baseURI  = ioService.newURI(base, null, null);
  4479.  
  4480.   return ioService.newURI(baseURI.resolve(url), null, null).spec;
  4481. }
  4482.  
  4483. function saveFrameDocument()
  4484. {
  4485.   var focusedWindow = document.commandDispatcher.focusedWindow;
  4486.   if (isContentFrame(focusedWindow))
  4487.     saveDocument(focusedWindow.document);
  4488. }
  4489.  
  4490. /*
  4491.  * Note that most of this routine has been moved into C++ in order to
  4492.  * be available for all <browser> tags as well as gecko embedding. See
  4493.  * mozilla/content/base/src/nsContentAreaDragDrop.cpp.
  4494.  *
  4495.  * Do not add any new fuctionality here other than what is needed for
  4496.  * a standalone product.
  4497.  */
  4498.  
  4499. var contentAreaDNDObserver = {
  4500.   onDrop: function (aEvent, aXferData, aDragSession)
  4501.     {
  4502.       var url = transferUtils.retrieveURLFromData(aXferData.data, aXferData.flavour.contentType);
  4503.  
  4504.       // valid urls don't contain spaces ' '; if we have a space it
  4505.       // isn't a valid url, or if it's a javascript: or data: url,
  4506.       // bail out
  4507.       if (!url || !url.length || url.indexOf(" ", 0) != -1 ||
  4508.           /^\s*(javascript|data):/.test(url))
  4509.         return;
  4510.  
  4511.       getBrowser().dragDropSecurityCheck(aEvent, aDragSession, url);
  4512.  
  4513.       switch (document.firstChild.getAttribute('windowtype')) {
  4514.         case "navigator:browser":
  4515.           var postData = { };
  4516.           var uri = getShortcutOrURI(url, postData);
  4517.           loadURI(uri, null, postData.value);
  4518.           break;
  4519.         case "navigator:view-source":
  4520.           viewSource(url);
  4521.           break;
  4522.       }
  4523.       
  4524.       // keep the event from being handled by the dragDrop listeners
  4525.       // built-in to gecko if they happen to be above us.    
  4526.       aEvent.preventDefault();
  4527.     },
  4528.  
  4529.   getSupportedFlavours: function ()
  4530.     {
  4531.       var flavourSet = new FlavourSet();
  4532.       flavourSet.appendFlavour("text/x-moz-url");
  4533.       flavourSet.appendFlavour("text/unicode");
  4534.       flavourSet.appendFlavour("application/x-moz-file", "nsIFile");
  4535.       return flavourSet;
  4536.     }
  4537.   
  4538. };
  4539.  
  4540. // For extensions
  4541. function getBrowser()
  4542. {
  4543.   if (!gBrowser)
  4544.     gBrowser = document.getElementById("content");
  4545.   return gBrowser;
  4546. }
  4547.  
  4548. function MultiplexHandler(event)
  4549. { try {
  4550.     var node = event.target;
  4551.     var name = node.getAttribute('name');
  4552.  
  4553.     if (name == 'detectorGroup') {
  4554.         SetForcedDetector(true);
  4555.         SelectDetector(event, false);
  4556.     } else if (name == 'charsetGroup') {
  4557.         var charset = node.getAttribute('id');
  4558.         charset = charset.substring('charset.'.length, charset.length)
  4559.         SetForcedCharset(charset);
  4560.         SetDefaultCharacterSet(charset);
  4561.     } else if (name == 'charsetCustomize') {
  4562.         //do nothing - please remove this else statement, once the charset prefs moves to the pref window
  4563.     } else {
  4564.         SetForcedCharset(node.getAttribute('id'));
  4565.         SetDefaultCharacterSet(node.getAttribute('id'));
  4566.     }
  4567.     } catch(ex) { alert(ex); }
  4568. }
  4569.  
  4570. function SetDefaultCharacterSet(charset)
  4571. {
  4572.     BrowserSetDefaultCharacterSet(charset);
  4573. }
  4574.  
  4575. function SelectDetector(event, doReload)
  4576. {
  4577.     var uri =  event.target.getAttribute("id");
  4578.     var prefvalue = uri.substring('chardet.'.length, uri.length);
  4579.     if ("off" == prefvalue) { // "off" is special value to turn off the detectors
  4580.         prefvalue = "";
  4581.     }
  4582.  
  4583.     try {
  4584.         var pref = Components.classes["@mozilla.org/preferences-service;1"]
  4585.                              .getService(Components.interfaces.nsIPrefBranch);
  4586.         var str =  Components.classes["@mozilla.org/supports-string;1"]
  4587.                              .createInstance(Components.interfaces.nsISupportsString);
  4588.  
  4589.         str.data = prefvalue;
  4590.         pref.setComplexValue("intl.charset.detector",
  4591.                              Components.interfaces.nsISupportsString, str);
  4592.         if (doReload) window._content.location.reload();
  4593.     }
  4594.     catch (ex) {
  4595.         dump("Failed to set the intl.charset.detector preference.\n");
  4596.     }
  4597. }
  4598.  
  4599. function SetForcedDetector(doReload)
  4600. {
  4601.     BrowserSetForcedDetector(doReload);
  4602. }
  4603.  
  4604. function SetForcedCharset(charset)
  4605. {
  4606.     BrowserSetForcedCharacterSet(charset);
  4607. }
  4608.  
  4609. function BrowserSetDefaultCharacterSet(aCharset)
  4610. {
  4611.   // no longer needed; set when setting Force; see bug 79608
  4612. }
  4613.  
  4614. function BrowserSetForcedCharacterSet(aCharset)
  4615. {
  4616.   var docCharset = getBrowser().docShell.QueryInterface(
  4617.                             Components.interfaces.nsIDocCharset);
  4618.   docCharset.charset = aCharset;
  4619.   BrowserReloadWithFlags(nsIWebNavigation.LOAD_FLAGS_CHARSET_CHANGE);
  4620. }
  4621.  
  4622. function BrowserSetForcedDetector(doReload)
  4623. {
  4624.   getBrowser().documentCharsetInfo.forcedDetector = true;
  4625.   if (doReload)
  4626.     BrowserReloadWithFlags(nsIWebNavigation.LOAD_FLAGS_CHARSET_CHANGE);
  4627. }
  4628.  
  4629. function UpdateCurrentCharset()
  4630. {
  4631.     var menuitem = null;
  4632.  
  4633.     // exctract the charset from DOM
  4634.     var wnd = document.commandDispatcher.focusedWindow;
  4635.     if ((window == wnd) || (wnd == null)) wnd = window._content;
  4636.     menuitem = document.getElementById('charset.' + wnd.document.characterSet);
  4637.  
  4638.     if (menuitem) {
  4639.         // uncheck previously checked item to workaround Mac checkmark problem
  4640.         // bug 98625
  4641.         if (gPrevCharset) {
  4642.             var pref_item = document.getElementById('charset.' + gPrevCharset);
  4643.             if (pref_item)
  4644.               pref_item.setAttribute('checked', 'false');
  4645.         }
  4646.         menuitem.setAttribute('checked', 'true');
  4647.     }
  4648. }
  4649.  
  4650. function UpdateCharsetDetector()
  4651. {
  4652.     var prefvalue;
  4653.  
  4654.     try {
  4655.         var pref = Components.classes["@mozilla.org/preferences-service;1"]
  4656.                              .getService(Components.interfaces.nsIPrefBranch);
  4657.         prefvalue = pref.getComplexValue("intl.charset.detector",
  4658.                                          Components.interfaces.nsIPrefLocalizedString).data;
  4659.     }
  4660.     catch (ex) {
  4661.         prefvalue = "";
  4662.     }
  4663.  
  4664.     if (prefvalue == "") prefvalue = "off";
  4665.     dump("intl.charset.detector = "+ prefvalue + "\n");
  4666.  
  4667.     prefvalue = 'chardet.' + prefvalue;
  4668.     var menuitem = document.getElementById(prefvalue);
  4669.  
  4670.     if (menuitem) {
  4671.         menuitem.setAttribute('checked', 'true');
  4672.     }
  4673. }
  4674.  
  4675. function UpdateMenus(event)
  4676. {
  4677.     // use setTimeout workaround to delay checkmark the menu
  4678.     // when onmenucomplete is ready then use it instead of oncreate
  4679.     // see bug 78290 for the detail
  4680.     UpdateCurrentCharset();
  4681.     setTimeout(UpdateCurrentCharset, 0);
  4682.     UpdateCharsetDetector();
  4683.     setTimeout(UpdateCharsetDetector, 0);
  4684. }
  4685.  
  4686. function CreateMenu(node)
  4687. {
  4688.   var observerService = Components.classes["@mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService);
  4689.   observerService.notifyObservers(null, "charsetmenu-selected", node);
  4690. }
  4691.  
  4692. function charsetLoadListener (event)
  4693. {
  4694.     var charset = window._content.document.characterSet;
  4695.  
  4696.     if (charset.length > 0 && (charset != gLastBrowserCharset)) {
  4697.         if (!gCharsetMenu)
  4698.           gCharsetMenu = Components.classes['@mozilla.org/rdf/datasource;1?name=charset-menu'].getService().QueryInterface(Components.interfaces.nsICurrentCharsetListener);
  4699.         gCharsetMenu.SetCurrentCharset(charset);
  4700.         gPrevCharset = gLastBrowserCharset;
  4701.         gLastBrowserCharset = charset;
  4702.     }
  4703. }
  4704.  
  4705.  
  4706. /* Begin Page Style Functions */
  4707. function getStyleSheetArray(frame)
  4708. {
  4709.   var styleSheets = frame.document.styleSheets;
  4710.   var styleSheetsArray = new Array(styleSheets.length);
  4711.   for (var i = 0; i < styleSheets.length; i++) {
  4712.     styleSheetsArray[i] = styleSheets[i];
  4713.   }
  4714.   return styleSheetsArray;
  4715. }
  4716.  
  4717. function getAllStyleSheets(frameset)
  4718. {
  4719.   var styleSheetsArray = getStyleSheetArray(frameset);
  4720.   for (var i = 0; i < frameset.frames.length; i++) {
  4721.     var frameSheets = getAllStyleSheets(frameset.frames[i]);
  4722.     styleSheetsArray = styleSheetsArray.concat(frameSheets);
  4723.   }
  4724.   return styleSheetsArray;
  4725. }
  4726.  
  4727. function stylesheetFillPopup(menuPopup)
  4728. {
  4729.   var noStyle = menuPopup.firstChild;
  4730.   var persistentOnly = noStyle.nextSibling;
  4731.   var sep = persistentOnly.nextSibling;
  4732.   while (sep.nextSibling)
  4733.     menuPopup.removeChild(sep.nextSibling);
  4734.  
  4735.   var styleSheets = getAllStyleSheets(window._content);
  4736.   var currentStyleSheets = [];
  4737.   var styleDisabled = getMarkupDocumentViewer().authorStyleDisabled;
  4738.   var haveAltSheets = false;
  4739.   var altStyleSelected = false;
  4740.   
  4741.   for (var i = 0; i < styleSheets.length; ++i) {
  4742.     var currentStyleSheet = styleSheets[i];
  4743.     
  4744.     // Skip any stylesheets that don't match the screen media type.
  4745.     var media = currentStyleSheet.media.mediaText.toLowerCase();
  4746.     if (media && (media.indexOf("screen") == -1) && (media.indexOf("all") == -1))
  4747.         continue;
  4748.         
  4749.     if (currentStyleSheet.title) {
  4750.       if (!currentStyleSheet.disabled)
  4751.         altStyleSelected = true;
  4752.  
  4753.       haveAltSheets = true;
  4754.       
  4755.       var lastWithSameTitle = null;
  4756.       if (currentStyleSheet.title in currentStyleSheets)
  4757.         lastWithSameTitle = currentStyleSheets[currentStyleSheet.title];
  4758.  
  4759.       if (!lastWithSameTitle) {
  4760.         var menuItem = document.createElement("menuitem");
  4761.         menuItem.setAttribute("type", "radio");
  4762.         menuItem.setAttribute("label", currentStyleSheet.title);
  4763.         menuItem.setAttribute("data", currentStyleSheet.title);
  4764.         menuItem.setAttribute("checked", !currentStyleSheet.disabled && !styleDisabled);
  4765.         menuPopup.appendChild(menuItem);
  4766.         currentStyleSheets[currentStyleSheet.title] = menuItem;
  4767.       } else {
  4768.         if (currentStyleSheet.disabled)
  4769.           lastWithSameTitle.removeAttribute("checked");
  4770.       }
  4771.     }
  4772.   }
  4773.   
  4774.   noStyle.setAttribute("checked", styleDisabled);
  4775.   persistentOnly.setAttribute("checked", !altStyleSelected && !styleDisabled);
  4776.   persistentOnly.hidden = (window._content.document.preferredStylesheetSet) ? true : false;
  4777.   sep.hidden = (noStyle.hidden && persistentOnly.hidden) || !haveAltSheets;
  4778.   return true;
  4779. }
  4780.  
  4781. function stylesheetInFrame(frame, title) {
  4782.   var docStyleSheets = frame.document.styleSheets;
  4783.  
  4784.   for (var i = 0; i < docStyleSheets.length; ++i) {
  4785.     if (docStyleSheets[i].title == title)
  4786.       return true;
  4787.   }
  4788.   return false;
  4789. }
  4790.  
  4791. function stylesheetSwitchFrame(frame, title) {
  4792.   var docStyleSheets = frame.document.styleSheets;
  4793.  
  4794.   for (var i = 0; i < docStyleSheets.length; ++i) {
  4795.     var docStyleSheet = docStyleSheets[i];
  4796.  
  4797.     if (title == "_nostyle")
  4798.       docStyleSheet.disabled = true;
  4799.     else if (docStyleSheet.title)
  4800.       docStyleSheet.disabled = (docStyleSheet.title != title);
  4801.     else if (docStyleSheet.disabled)
  4802.       docStyleSheet.disabled = false;
  4803.   }
  4804. }
  4805.  
  4806. function stylesheetSwitchAll(frameset, title) {
  4807.   if (!title || title == "_nostyle" || stylesheetInFrame(frameset, title)) {
  4808.     stylesheetSwitchFrame(frameset, title);
  4809.   }
  4810.   for (var i = 0; i < frameset.frames.length; i++) {
  4811.     stylesheetSwitchAll(frameset.frames[i], title);
  4812.   }
  4813. }
  4814.  
  4815. function setStyleDisabled(disabled) {
  4816.   getMarkupDocumentViewer().authorStyleDisabled = disabled;
  4817. }
  4818.  
  4819. /* End of the Page Style functions */
  4820.  
  4821. function clearObsoletePrefs()
  4822. {  
  4823.   // removed 10/03/2003
  4824.   try {
  4825.     PREF.clearUserPref("timebomb.first_launch_time");
  4826.   } catch (e) {}
  4827.  
  4828.   // removed 10/16/2003
  4829.   // migrate firebird cookie prefs, if they exist.
  4830.   try {
  4831.     PREF.clearUserPref("network.cookie.enable");
  4832.     // No error: it means this pref was not the default one, cookie were disabled.
  4833.     PREF.SetIntPref("network.cookie.cookieBehavior", 2);
  4834.   } catch (e) {
  4835.     try {
  4836.       PREF.clearUserPref("network.cookie.enableForOriginatingWebsiteOnly");
  4837.       // No error: it means that enableForOriginatingWebsiteOnly was true.
  4838.       PREF.SetIntPref("network.cookie.cookieBehavior", 1);
  4839.     } catch (e) {
  4840.     // here, either we already have migrated the cookie pref
  4841.     // or the new and old behavior are the same (0). In any case: nothing to do.
  4842.     }
  4843.   }
  4844.  
  4845.   // removed 03/09/2003
  4846.   // last of the forked cookie prefs
  4847.   try {
  4848.     PREF.clearUserPref("network.cookie.enableForCurrentSessionOnly");
  4849.     // No error, therefore we were limiting cookies to session
  4850.     PREF.setIntPref("network.cookie.lifetimePolicy", 2);
  4851.   } catch (e) {
  4852.     // nothing to do in this case
  4853.   }
  4854.  
  4855.   try {
  4856.     PREF.clearUserPref("network.cookie.warnAboutCookies");
  4857.     // No error: the pref is set to ask for cookies, set the correct pref
  4858.     // This will replace the setting if enableForCurrentSessionOnly was
  4859.     // also true, because dialogs explictly allow accepting for session
  4860.     PREF.setIntPref("network.cookie.lifetimePolicy", 1);
  4861.   } catch (e) {
  4862.     // nothing to do in this case
  4863.   }
  4864.  
  4865.   // removed 10/22/2003
  4866.   try {
  4867.     PREF.clearUserPref("browser.search.defaultengine");
  4868.   } catch (e) {}
  4869.  
  4870.   // removed 11/01/2003
  4871.   try {
  4872.     PREF.clearUserPref("print.use_global_printsettings");
  4873.   } catch (e) {}
  4874.   try {
  4875.     PREF.clearUserPref("print.save_print_settings");
  4876.   } catch (e) {}
  4877.  
  4878. }
  4879.  
  4880. var BrowserOffline = {
  4881.   /////////////////////////////////////////////////////////////////////////////
  4882.   // BrowserOffline Public Methods
  4883.   init: function ()
  4884.   {
  4885.     var os = Components.classes["@mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService);
  4886.     os.addObserver(this, "network:offline-status-changed", false);
  4887.  
  4888.     if (!this._uiElement)
  4889.       this._uiElement = document.getElementById("goOfflineMenuitem");
  4890.  
  4891.     // set the initial state
  4892.     var ioService = Components.classes["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService);
  4893.     var isOffline = false;
  4894.     try {
  4895.       isOffline = gPrefService.getBoolPref("browser.offline");
  4896.     }
  4897.     catch (e) { }
  4898.     ioService.offline = isOffline;
  4899.  
  4900.     this._updateOfflineUI(isOffline);
  4901.   },
  4902.   
  4903.   uninit: function ()
  4904.   {
  4905.     try {
  4906.       var os = Components.classes["@mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService);
  4907.       os.removeObserver(this, "network:offline-status-changed");
  4908.     } catch (ex) {
  4909.     }
  4910.   },
  4911.  
  4912.   toggleOfflineStatus: function ()
  4913.   {
  4914.     if (!this._canGoOffline()) {
  4915.       this._updateOfflineUI(false);
  4916.       return;
  4917.     }
  4918.  
  4919.     var ioService = Components.classes["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService);
  4920.     ioService.offline = !ioService.offline;
  4921.     
  4922.     gPrefService.setBoolPref("browser.offline", ioService.offline);
  4923.   },
  4924.   
  4925.   /////////////////////////////////////////////////////////////////////////////
  4926.   // nsIObserver
  4927.   observe: function (aSubject, aTopic, aState) 
  4928.   {
  4929.     if (aTopic != "network:offline-status-changed")
  4930.       return;
  4931.     
  4932.     this._updateOfflineUI(aState == "offline");
  4933.   },
  4934.  
  4935.   /////////////////////////////////////////////////////////////////////////////
  4936.   // BrowserOffline Implementation Methods
  4937.   _canGoOffline: function ()
  4938.   {
  4939.     var os = Components.classes["@mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService);
  4940.     if (os) {
  4941.       try {
  4942.         var cancelGoOffline = Components.classes["@mozilla.org/supports-PRBool;1"].createInstance(Components.interfaces.nsISupportsPRBool);
  4943.         os.notifyObservers(cancelGoOffline, "offline-requested", null);
  4944.         
  4945.         // Something aborted the quit process. 
  4946.         if (cancelGoOffline.data)
  4947.           return false;
  4948.       }
  4949.       catch (ex) {
  4950.       }
  4951.     }
  4952.     return true;
  4953.   },
  4954.  
  4955.   _uiElement: null,
  4956.   _updateOfflineUI: function (aOffline)
  4957.   {
  4958.     var offlineLocked = gPrefService.prefIsLocked("network.online");
  4959.     if (offlineLocked) 
  4960.       this._uiElement.setAttribute("disabled", "true");
  4961.       
  4962.     this._uiElement.setAttribute("checked", aOffline);
  4963.   }
  4964. };
  4965.  
  4966. function WindowIsClosing()
  4967. {
  4968.   var browser = getBrowser();
  4969.   var cn = browser.tabContainer.childNodes;
  4970.   var numtabs = cn.length;
  4971.   var reallyClose = browser.warnAboutClosingTabs(true);
  4972.  
  4973.   for (var i = 0; reallyClose && i < numtabs; ++i) {
  4974.     var ds = browser.getBrowserForTab(cn[i]).docShell;
  4975.  
  4976.     if (ds.contentViewer && !ds.contentViewer.permitUnload())
  4977.       reallyClose = false;
  4978.   }
  4979.  
  4980.   if (reallyClose)
  4981.     return closeWindow(false);
  4982.  
  4983.   return reallyClose;
  4984. }
  4985.  
  4986. var MailIntegration = {
  4987.   sendLinkForContent: function ()
  4988.   {
  4989.     this.sendMessage(Components.lookupMethod(window._content, 'location').call(window._content).href,
  4990.                      Components.lookupMethod(window._content.document, 'title').call(window._content.document));  
  4991.   },
  4992.  
  4993.   sendMessage: function (aBody, aSubject) 
  4994.   {
  4995.     // generate a mailto url based on the url and the url's title
  4996.     var mailtoUrl = aBody ? "mailto:?body=" + encodeURIComponent(aBody) + "&subject=" + encodeURIComponent(aSubject) : "mailto:";
  4997.  
  4998.     var ioService = Components.classes["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService);
  4999.     var uri = ioService.newURI(mailtoUrl, null, null);
  5000.  
  5001.     // now pass this url to the operating system
  5002.     this._launchExternalUrl(uri); 
  5003.   },
  5004.  
  5005.   // a generic method which can be used to pass arbitrary urls to the operating system.
  5006.   // aURL --> a nsIURI which represents the url to launch
  5007.   _launchExternalUrl: function(aURL)
  5008.   {
  5009.     var extProtocolSvc = Components.classes["@mozilla.org/uriloader/external-protocol-service;1"].getService(Components.interfaces.nsIExternalProtocolService);
  5010.     if (extProtocolSvc)
  5011.       extProtocolSvc.loadUrl(aURL);
  5012.   },
  5013.   
  5014.   readMail: function ()
  5015.   {
  5016.     var shell = getShellService();
  5017.     if (shell)
  5018.       shell.openPreferredApplication(Components.interfaces.nsIShellService.APPLICATION_MAIL);
  5019.   },
  5020.   
  5021.   readNews: function ()
  5022.   {
  5023.     var shell = getShellService();
  5024.     if (shell)
  5025.       shell.openPreferredApplication(Components.interfaces.nsIShellService.APPLICATION_NEWS);
  5026.   },
  5027.   
  5028.   updateUnreadCount: function ()
  5029.   {
  5030.     var shell = Components.classes["@mozilla.org/browser/shell-service;1"]
  5031.                           .getService(Components.interfaces.nsIWindowsShellService);
  5032.     var unreadCount = shell.unreadMailCount;
  5033.     var message = gNavigatorBundle.getFormattedString("mailUnreadTooltip", [unreadCount]);
  5034.     var element = document.getElementById("mail-button");
  5035.     if (element)
  5036.       element.setAttribute("tooltiptext", message);
  5037.                                                               
  5038.     message = gNavigatorBundle.getFormattedString("mailUnreadMenuitem", [unreadCount]);
  5039.     element = document.getElementById("Browser:ReadMail");
  5040.     element.setAttribute("label", message);
  5041.   }
  5042. };
  5043.  
  5044. function BrowserOpenExtensions(aOpenMode)
  5045. {
  5046.   const EMTYPE = "Extension:Manager";
  5047.   
  5048.   var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
  5049.                      .getService(Components.interfaces.nsIWindowMediator);
  5050.   var needToOpen = true;
  5051.   var windowType = EMTYPE + "-" + aOpenMode;
  5052.   var windows = wm.getEnumerator(windowType);
  5053.   while (windows.hasMoreElements()) {
  5054.     var theEM = windows.getNext().QueryInterface(Components.interfaces.nsIDOMWindowInternal);
  5055.     if (theEM.document.documentElement.getAttribute("windowtype") == windowType) {
  5056.       theEM.focus();
  5057.       needToOpen = false;
  5058.       break;
  5059.     }
  5060.   }
  5061.  
  5062.   if (needToOpen) {
  5063.     const EMURL = "chrome://mozapps/content/extensions/extensions.xul?type=" + aOpenMode;
  5064.     const EMFEATURES = "chrome,dialog=no,resizable";
  5065.     window.openDialog(EMURL, "", EMFEATURES);
  5066.   }
  5067. }
  5068.  
  5069. function AddKeywordForSearchField()
  5070. {
  5071.   var node = document.popupNode;
  5072.   var ioService = Components.classes["@mozilla.org/network/io-service;1"]
  5073.                             .getService(Components.interfaces.nsIIOService);
  5074.   var uri = Components.classes["@mozilla.org/network/standard-url;1"]
  5075.                       .getService(Components.interfaces.nsIURI);
  5076.   uri.spec = node.ownerDocument.URL;
  5077.   
  5078.   var keywordURL = ioService.newURI(node.form.action, node.ownerDocument.characterSet, uri);
  5079.   var spec = keywordURL.spec;
  5080.   var postData = "";
  5081.   
  5082.   if (node.form.method.toUpperCase() == "POST" && 
  5083.       (node.form.enctype == "application/x-www-form-urlencoded" || node.form.enctype == "")) {
  5084.     for (var i = 0; i < node.form.elements.length; ++i) {
  5085.       var e = node.form.elements[i];
  5086.       if (e.type.toLowerCase() == "text" || e.type.toLowerCase() == "hidden" ||
  5087.           e instanceof HTMLTextAreaElement)
  5088.         postData += escape(e.name + "=" + (e == node ? "%s" : e.value)) + "&";
  5089.       else if (e instanceof HTMLSelectElement && e.selectedIndex >= 0)
  5090.         postData += escape(e.name + "=" + e.options[e.selectedIndex].value) + "&";
  5091.       else if ((e.type.toLowerCase() == "checkbox" ||
  5092.           e.type.toLowerCase() == "radio") && e.checked)
  5093.      postData += escape(e.name + "=" + e.value) + "&";
  5094.     }
  5095.   }
  5096.   else {
  5097.     spec += "?" + escape(node.name) + "=%s";
  5098.     for (var i = 0; i < node.form.elements.length; ++i) {
  5099.       var e = node.form.elements[i];
  5100.       if (e == node) // avoid duplication of the target field value, which was populated above.
  5101.         continue;
  5102.         
  5103.       if (e.type.toLowerCase() == "text" || e.type.toLowerCase() == "hidden" ||
  5104.           e instanceof HTMLTextAreaElement)
  5105.         spec += "&" + escape(e.name) + "=" + escape(e.value);
  5106.       else if (e instanceof HTMLSelectElement && e.selectedIndex >= 0)
  5107.         spec += "&" + escape(e.name) + "=" + escape(e.options[e.selectedIndex].value);
  5108.       else if ((e.type.toLowerCase() == "checkbox" ||
  5109.           e.type.toLowerCase() == "radio") && e.checked)
  5110.      spec += "&" + escape(e.name) + "=" + escape(e.value);
  5111.     }
  5112.   }
  5113.   openDialog("chrome://browser/content/bookmarks/addBookmark2.xul", "",
  5114.              "centerscreen,chrome,dialog,resizable,dependent",
  5115.              "", spec, null, node.ownerDocument.characterSet, null, null, 
  5116.              false, "", true, postData);
  5117. }
  5118.  
  5119. /////////////// livemark handling
  5120.  
  5121. // XXX this event listener can/should probably be combined with the onLinkAdded
  5122. // listener in tabbrowser.xml, which only listens for favicons and then passes
  5123. // them to onLinkIconAvailable in the ProgressListener.  We could extend the
  5124. // progress listener to have a generic onLinkAvailable and have tabbrowser pass
  5125. // along all events.  It should give us the browser for the tab, as well as
  5126. // the actual event.
  5127. function livemarkOnLinkAdded(event)
  5128. {
  5129.   if (!event.isTrusted)
  5130.     return;
  5131.  
  5132.   if (!gLivemarksButton)
  5133.     gLivemarksButton = document.getElementById("livemark-button");
  5134.  
  5135.   // from tabbrowser.xml
  5136.   // mechanism for reading properties of the underlying XPCOM object
  5137.   // (ignoring potential getters/setters added by malicious content)
  5138.   var safeGetProperty = function(obj, propname) {
  5139.     return Components.lookupMethod(obj, propname).call(obj);
  5140.   }
  5141.  
  5142.   var erel = event.target.rel;
  5143.   var etype = event.target.type;
  5144.   var etitle = event.target.title;
  5145.  
  5146.   // this is a blogger post service URL; so skip it
  5147.   if (erel && erel == "service.post")
  5148.     return;
  5149.  
  5150.   if (etype == "application/rss+xml" ||
  5151.       etype == "application/atom+xml" ||
  5152.       etype == "application/x.atom+xml" ||
  5153.       etitle.indexOf("RSS") != -1 ||
  5154.       etitle.indexOf("Atom") != -1 ||
  5155.       etitle.indexOf("rss") != -1)
  5156.   {
  5157.     const targetDoc = safeGetProperty(event.target, "ownerDocument");
  5158.  
  5159.     // find which tab this is for, and set the attribute on the browser
  5160.     // should there be a getTabForDocument method on tabbedbrowser?
  5161.     var browserForLink = null;
  5162.     if (gBrowser.mTabbedMode) {
  5163.       var browserIndex = gBrowser.getBrowserIndexForDocument(targetDoc);
  5164.       if (browserIndex == -1)
  5165.         return;
  5166.       browserForLink = gBrowser.getBrowserAtIndex(browserIndex);
  5167.     } else if (gBrowser.mCurrentBrowser.contentDocument == targetDoc) {
  5168.       browserForLink = gBrowser.mCurrentBrowser;
  5169.     }
  5170.  
  5171.     if (!browserForLink) {
  5172.       // ??? this really shouldn't happen..
  5173.       return;
  5174.     }
  5175.  
  5176.     var livemarkLinks = [];
  5177.     if (browserForLink.livemarkLinks != null) {
  5178.       livemarkLinks = browserForLink.livemarkLinks;
  5179.     }
  5180.  
  5181.     var wrapper = new XPCNativeWrapper(event.target, "href", "type", "title");
  5182.  
  5183.     livemarkLinks.push({ href: wrapper.href,
  5184.                          type: wrapper.type,
  5185.                         title: wrapper.title});
  5186.  
  5187.     browserForLink.livemarkLinks = livemarkLinks;
  5188.     if (browserForLink == gBrowser || browserForLink == gBrowser.mCurrentBrowser)
  5189.       gLivemarksButton.setAttribute("livemarks", "true");
  5190.   }
  5191. }
  5192.  
  5193. // this is called both from onload and also whenever the user
  5194. // switches tabs; we update whether we show or hide the livemark
  5195. // button based on whether the window has livemarks set.
  5196. function updatePageLivemarks()
  5197. {
  5198.   if (!gLivemarksButton)
  5199.     gLivemarksButton = document.getElementById("livemark-button");
  5200.  
  5201.   var livemarkLinks = gBrowser.mCurrentBrowser.livemarkLinks;
  5202.   if (!livemarkLinks || livemarkLinks.length == 0) {
  5203.     gLivemarksButton.removeAttribute("livemarks");
  5204.     gLivemarksButton.setAttribute("tooltiptext", gNavigatorBundle.getString("livemarkNoLivemarksTooltip"));
  5205.   } else {
  5206.     gLivemarksButton.setAttribute("livemarks", "true");
  5207.     gLivemarksButton.setAttribute("tooltiptext", gNavigatorBundle.getString("livemarkHasLivemarksTooltip"));
  5208.   }
  5209. }
  5210.  
  5211. function livemarkFillPopup(menuPopup)
  5212. {
  5213.   var livemarkLinks = gBrowser.mCurrentBrowser.livemarkLinks;
  5214.   if (livemarkLinks == null) {
  5215.     // XXX hack -- menu opening depends on setting of an "open"
  5216.     // attribute, and the menu refuses to open if that attribute is
  5217.     // set (because it thinks it's already open).  onpopupshowing gets
  5218.     // called after the attribute is unset, and it doesn't get unset
  5219.     // if we return false.  so we unset it here; otherwise, the menu
  5220.     // refuses to work past this point.
  5221.     menuPopup.parentNode.removeAttribute("open");
  5222.     return false;
  5223.   }
  5224.  
  5225.   while (menuPopup.firstChild) {
  5226.     menuPopup.removeChild(menuPopup.firstChild);
  5227.   }
  5228.  
  5229.   for (var i = 0; i < livemarkLinks.length; i++) {
  5230.     var markinfo = livemarkLinks[i];
  5231.  
  5232.     var menuItem = document.createElement("menuitem");
  5233.     var baseTitle = markinfo.title || markinfo.href;
  5234.     var labelStr = gNavigatorBundle.getFormattedString("livemarkSubscribeTo", [baseTitle]);
  5235.     menuItem.setAttribute("label", labelStr);
  5236.     menuItem.setAttribute("data", markinfo.href);
  5237.     menuItem.setAttribute("tooltiptext", markinfo.href);
  5238.     menuPopup.appendChild(menuItem);
  5239.   }
  5240.  
  5241.   return true;
  5242. }
  5243.  
  5244. function livemarkAddMark(wincontent, data) {
  5245.   var title = wincontent.document.title;
  5246.   BookmarksUtils.addLivemark(wincontent.document.baseURI, data, title);
  5247. }
  5248.  
  5249. function updatePageFavIcon(aBrowser, aListener) {
  5250.   var uri = aBrowser.currentURI;
  5251.  
  5252.   if (!gBrowser.shouldLoadFavIcon(uri))
  5253.     return;
  5254.  
  5255.   // if we made it here with this null, then no <link> was found for
  5256.   // the page load.  We try to fetch a generic favicon.ico.
  5257.   if (aBrowser.mFavIconURL == null) {
  5258.     aBrowser.mFavIconURL = gBrowser.buildFavIconString(uri);
  5259.     // give it to the listener as well
  5260.     // XXX - there is no listener for non-tabbed-mode: this is why
  5261.     // the urlbar has no favicon when you switch from tabbed mode to
  5262.     // non-tabbed-mode.
  5263.     if (aListener)
  5264.       aListener.mIcon = aBrowser.mFavIconURL;
  5265.   }
  5266.  
  5267.   if (aBrowser == gBrowser.mCurrentBrowser)
  5268.     PageProxySetIcon(aBrowser.mFavIconURL);
  5269.  
  5270.   if (aBrowser.mFavIconURL != null)
  5271.     BookmarksUtils.loadFavIcon(uri.spec, aBrowser.mFavIconURL);
  5272. }
  5273.  
  5274. function getUILink(item)
  5275. {
  5276.   var regionBundle = document.getElementById("bundle_browser_region");
  5277.  
  5278.   if (item == "tellAFriend")
  5279.     return regionBundle.getString("tellAFriendURL");
  5280.   
  5281.   if (item == "promote")
  5282.     return regionBundle.getString("promoteURL");
  5283.   
  5284.   return "";
  5285. }
  5286.  
  5287. function isBidiEnabled(){
  5288.   var rv = false;
  5289.  
  5290.   var systemLocale;
  5291.   try {
  5292.     var localService = Components.classes["@mozilla.org/intl/nslocaleservice;1"]
  5293.                                  .getService(Components.interfaces.nsILocaleService);
  5294.     systemLocale = localService.getSystemLocale().getCategory("NSILOCALE_CTYPE").substr(0,3);
  5295.   } catch (e){}
  5296.  
  5297.   rv = ( (systemLocale == "he-") || (systemLocale == "ar-") || (systemLocale == "syr") ||
  5298.          (systemLocale == "fa-") || (systemLocale == "ur-") );
  5299.  
  5300.   if (!rv) {
  5301.     // check the overriding pref
  5302.     var mPrefs = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranch);
  5303.     try {
  5304.       rv = mPrefs.getBoolPref("bidi.browser.ui");
  5305.     }
  5306.     catch (e){}
  5307.   }
  5308.  
  5309.   return rv;
  5310. }
  5311.  
  5312. function GetFrameDocumentsFromWindow(aWindow){
  5313.  if (aWindow.getComputedStyle(aWindow.document.body, "").direction == "ltr")
  5314.     aWindow.document.dir = "rtl";
  5315.   else
  5316.     aWindow.document.dir = "ltr";
  5317.  
  5318.   for (var run = 0; run < aWindow.frames.length; run++)
  5319.     GetFrameDocumentsFromWindow(aWindow.frames[run]);
  5320. }
  5321.  
  5322. function SwitchDocumentDirection(){
  5323.   GetFrameDocumentsFromWindow(window.content);
  5324. }
  5325.  
  5326. function SwitchFocusedTextEntryDirection() {
  5327.   if (isBidiEnabled())
  5328.   {
  5329.     var focusedElement = document.commandDispatcher.focusedElement;
  5330.     if (focusedElement)
  5331.       if (window.getComputedStyle(focusedElement, "").direction == "ltr")
  5332.         focusedElement.style.direction = "rtl";
  5333.       else
  5334.         focusedElement.style.direction = "ltr";
  5335.   }
  5336. }
  5337.  
  5338.  
  5339. function missingPluginInstaller(){
  5340.   this.missingPlugins = new Object();
  5341. }
  5342.  
  5343. missingPluginInstaller.prototype.installSinglePlugin = function(aEvent){
  5344.   // Check if the event is trust-worthy.
  5345.   if (!aEvent.isTrusted) {
  5346.     return;
  5347.   }
  5348.  
  5349.   var tabbrowser = getBrowser();
  5350.   var missingPluginsArray = new Object;
  5351.  
  5352.   var tagMimetype;
  5353.   var pluginsPage;
  5354.   if (aEvent.target instanceof HTMLAppletElement) {
  5355.     tagMimetype = "application/x-java-vm";
  5356.   } else if (aEvent.target instanceof HTMLObjectElement) {
  5357.     tagMimetype = aEvent.target.type;
  5358.     pluginsPage = aEvent.target.getAttribute("codebase");
  5359.   } else {
  5360.     tagMimetype = aEvent.target.type;
  5361.     pluginsPage = aEvent.target.getAttribute("pluginspage");
  5362.   }
  5363.  
  5364.   missingPluginsArray[tagMimetype] = {mimetype: tagMimetype, pluginsPage: pluginsPage};
  5365.  
  5366.   if (missingPluginsArray) {
  5367.     window.openDialog("chrome://mozapps/content/plugins/pluginInstallerWizard.xul",
  5368.       "PFSWindow", "modal,chrome,resizable=yes", {plugins: missingPluginsArray, tab: tabbrowser.mCurrentTab});
  5369.   }            
  5370.  
  5371.   aEvent.preventDefault();
  5372. }
  5373.  
  5374. missingPluginInstaller.prototype.newMissingPlugin = function(aEvent){
  5375.   // Check if the event is trust-worthy.
  5376.   if (!aEvent.isTrusted) {
  5377.     return;
  5378.   }
  5379.  
  5380.   // For broken non-object plugin tags, register a click handler so
  5381.   // that the user can click the plugin replacement to get the new
  5382.   // plugin. Object tags can, and often do, deal with that themselves,
  5383.   // so don't stomp on the page developers toes.
  5384.  
  5385.   if (!(aEvent.target instanceof HTMLObjectElement)) {
  5386.     aEvent.target.addEventListener("click",
  5387.                                    gMissingPluginInstaller.installSinglePlugin,
  5388.                                    false);
  5389.   }
  5390.  
  5391.   var tabbrowser = getBrowser();
  5392.   const browsers = tabbrowser.mPanelContainer.childNodes;
  5393.  
  5394.   var window = aEvent.target.ownerDocument.__parent__;
  5395.   // walk up till the toplevel window
  5396.   while (window.parent != window)
  5397.     window = window.parent;
  5398.  
  5399.   var i = 0;
  5400.   for (; i < browsers.length; i++) {
  5401.     if (tabbrowser.getBrowserAtIndex(i).contentWindow == window)
  5402.       break;
  5403.   }
  5404.  
  5405.   var tab = tabbrowser.mTabContainer.childNodes[i];
  5406.  
  5407.   if (!gMissingPluginInstaller.missingPlugins)
  5408.     gMissingPluginInstaller.missingPlugins = new Object();
  5409.  
  5410.   if (!gMissingPluginInstaller.missingPlugins[tab])
  5411.     gMissingPluginInstaller.missingPlugins[tab] = new Object();
  5412.  
  5413.   var tagMimetype;
  5414.   var pluginsPage;
  5415.   if (aEvent.target instanceof HTMLAppletElement) {
  5416.     tagMimetype = "application/x-java-vm";
  5417.   } else if (aEvent.target instanceof HTMLObjectElement) {
  5418.     tagMimetype = aEvent.target.type;
  5419.     pluginsPage = aEvent.target.getAttribute("codebase");
  5420.   } else {
  5421.     tagMimetype = aEvent.target.type;
  5422.     pluginsPage = aEvent.target.getAttribute("pluginspage");
  5423.   }
  5424.  
  5425.   gMissingPluginInstaller.missingPlugins[tab][tagMimetype] = {
  5426.     mimetype: tagMimetype,
  5427.     pluginsPage: pluginsPage
  5428.   };
  5429.  
  5430.   var browser = tabbrowser.getBrowserAtIndex(i);
  5431.   var iconURL = "chrome://mozapps/skin/xpinstall/xpinstallItemGeneric.png";
  5432.   
  5433.   var bundle_browser = document.getElementById("bundle_browser");
  5434.   var messageString = bundle_browser.getString("missingpluginsMessage.title");
  5435.   var buttonString = bundle_browser.getString("missingpluginsMessage.button.label");
  5436.  
  5437.   tabbrowser.showMessage(browser, iconURL, messageString, buttonString, 
  5438.                          "", "missing-plugin", null, "top", true);
  5439. }
  5440.  
  5441. missingPluginInstaller.prototype.clearMissingPlugins = function(aTab){
  5442.   this.missingPlugins[aTab] = null;
  5443. }
  5444.  
  5445.  
  5446. missingPluginInstaller.prototype.observe = function(aSubject, aTopic, aData){
  5447.   switch (aTopic) {
  5448.     case "missing-plugin":
  5449.       // get the urls of missing plugins
  5450.       var tabbrowser = getBrowser();
  5451.       var missingPluginsArray = gMissingPluginInstaller.missingPlugins[tabbrowser.mCurrentTab];
  5452.  
  5453.       if (missingPluginsArray) {
  5454.         window.openDialog("chrome://mozapps/content/plugins/pluginInstallerWizard.xul",
  5455.           "PFSWindow", "modal,chrome,resizable=yes", {plugins: missingPluginsArray, tab: tabbrowser.mCurrentTab});
  5456.       }            
  5457.  
  5458.       tabbrowser.hideMessage(tabbrowser.selectedBrowser, "top");
  5459.       break;      
  5460.   }
  5461. }
  5462. var gMissingPluginInstaller = new missingPluginInstaller();
  5463.